Merge "Don't crash when backup timeout races with agent completion"
diff --git a/Android.mk b/Android.mk
index 44fdb77..669efc7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -174,9 +174,6 @@
 	core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
 	core/java/android/hardware/soundtrigger/IRecognitionStatusCallback.aidl \
 	core/java/android/hardware/usb/IUsbManager.aidl \
-	core/java/android/midi/IMidiDeviceServer.aidl \
-	core/java/android/midi/IMidiListener.aidl \
-	core/java/android/midi/IMidiManager.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
@@ -335,7 +332,10 @@
 	media/java/android/media/IRemoteVolumeObserver.aidl \
 	media/java/android/media/IRingtonePlayer.aidl \
 	media/java/android/media/IVolumeController.aidl \
-        media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/audiopolicy/IAudioPolicyCallback.aidl \
+	media/java/android/media/midi/IMidiDeviceServer.aidl \
+	media/java/android/media/midi/IMidiListener.aidl \
+	media/java/android/media/midi/IMidiManager.aidl \
 	media/java/android/media/projection/IMediaProjection.aidl \
 	media/java/android/media/projection/IMediaProjectionCallback.aidl \
 	media/java/android/media/projection/IMediaProjectionManager.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index c35f332..c812b6a 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -228,6 +228,11 @@
 $(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)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/bin/inputflinger $(PRODUCT_OUT)/symbols/system/bin/inputflinger)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/lib/libinputflingerhost.so $(PRODUCT_OUT)/system/lib64/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/symbols/system/lib/libinputflingerhost.so $(PRODUCT_OUT)/symbols/system/lib64/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libinputflingerhost.so $(PRODUCT_OUT)/obj_arm/lib/libinputflingerhost.so)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
 
 # ******************************************************************
 # 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 7d8b892..c7898e4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -886,6 +886,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
+    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -1711,6 +1712,7 @@
     field public static final int paste = 16908322; // 0x1020022
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908338; // 0x1020032
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1727,6 +1729,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908337; // 0x1020031
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -5530,6 +5533,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -11793,15 +11797,8 @@
     method public final void setTileModeY(android.graphics.Shader.TileMode);
   }
 
-  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     field public static final int HORIZONTAL = 1; // 0x1
     field public static final int VERTICAL = 2; // 0x2
   }
@@ -11843,8 +11840,10 @@
     method public android.graphics.Rect getDirtyBounds();
     method public boolean getDither();
     method public boolean getFilterBitmap();
+    method public void getHotspotBounds(android.graphics.Rect);
     method public int getIntrinsicHeight();
     method public int getIntrinsicWidth();
+    method public int getLayoutDirection();
     method public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
@@ -11862,6 +11861,7 @@
     method public void jumpToCurrentState();
     method public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
+    method public boolean onLayoutDirectionChange(int);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
@@ -11878,6 +11878,7 @@
     method public void setFilterBitmap(boolean);
     method public void setHotspot(float, float);
     method public void setHotspotBounds(int, int, int, int);
+    method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
     method public boolean setState(int[]);
     method public void setTint(int);
@@ -11942,6 +11943,19 @@
     method public final void setVariablePadding(boolean);
   }
 
+  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public DrawableWrapper(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    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(android.graphics.drawable.Drawable);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
@@ -11989,17 +12003,9 @@
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
   }
 
-  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -12012,6 +12018,12 @@
     method public int getId(int);
     method public int getLayerGravity(int);
     method public int getLayerHeight(int);
+    method public int getLayerInsetBottom(int);
+    method public int getLayerInsetEnd(int);
+    method public int getLayerInsetLeft(int);
+    method public int getLayerInsetRight(int);
+    method public int getLayerInsetStart(int);
+    method public int getLayerInsetTop(int);
     method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
@@ -12024,9 +12036,17 @@
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
     method public void setLayerGravity(int, int);
+    method public void setLayerHeight(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetBottom(int, int);
+    method public void setLayerInsetEnd(int, int);
+    method public void setLayerInsetLeft(int, int);
     method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerInsetRight(int, int);
+    method public void setLayerInsetStart(int, int);
+    method public void setLayerInsetTop(int, int);
     method public void setLayerSize(int, int, int);
+    method public void setLayerWidth(int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -12079,41 +12099,24 @@
     field public static final int RADIUS_AUTO = -1; // 0xffffffff
   }
 
-  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public RotateDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
     method public float getFromDegrees();
-    method public int getOpacity();
     method public float getPivotX();
     method public float getPivotY();
     method public float getToDegrees();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public boolean isPivotXRelative();
     method public boolean isPivotYRelative();
-    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(android.graphics.drawable.Drawable);
     method public void setFromDegrees(float);
     method public void setPivotX(float);
     method public void setPivotXRelative(boolean);
     method public void setPivotY(float);
     method public void setPivotYRelative(boolean);
     method public void setToDegrees(float);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
-  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
@@ -28745,6 +28748,7 @@
     method public boolean isInCall();
     method public void showInCallScreen(boolean);
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     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";
diff --git a/api/system-current.txt b/api/system-current.txt
index 6968896..f274a0d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -958,6 +958,7 @@
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
+    field public static final int numbersInnerTextColor = 16843999; // 0x10104df
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
     field public static final int numbersTextColor = 16843937; // 0x10104a1
     field public static final deprecated int numeric = 16843109; // 0x1010165
@@ -1787,6 +1788,7 @@
     field public static final int paste = 16908322; // 0x1020022
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908338; // 0x1020032
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1803,6 +1805,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908337; // 0x1020031
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -5631,6 +5634,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
@@ -12067,15 +12071,8 @@
     method public final void setTileModeY(android.graphics.Shader.TileMode);
   }
 
-  public class ClipDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ClipDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ClipDrawable(android.graphics.drawable.Drawable, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
     field public static final int HORIZONTAL = 1; // 0x1
     field public static final int VERTICAL = 2; // 0x2
   }
@@ -12117,8 +12114,10 @@
     method public android.graphics.Rect getDirtyBounds();
     method public boolean getDither();
     method public boolean getFilterBitmap();
+    method public void getHotspotBounds(android.graphics.Rect);
     method public int getIntrinsicHeight();
     method public int getIntrinsicWidth();
+    method public int getLayoutDirection();
     method public final int getLevel();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
@@ -12136,6 +12135,7 @@
     method public void jumpToCurrentState();
     method public android.graphics.drawable.Drawable mutate();
     method protected void onBoundsChange(android.graphics.Rect);
+    method public boolean onLayoutDirectionChange(int);
     method protected boolean onLevelChange(int);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
@@ -12152,6 +12152,7 @@
     method public void setFilterBitmap(boolean);
     method public void setHotspot(float, float);
     method public void setHotspotBounds(int, int, int, int);
+    method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
     method public boolean setState(int[]);
     method public void setTint(int);
@@ -12216,6 +12217,19 @@
     method public final void setVariablePadding(boolean);
   }
 
+  public abstract class DrawableWrapper extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+    ctor public DrawableWrapper(android.graphics.drawable.Drawable);
+    method public void draw(android.graphics.Canvas);
+    method public android.graphics.drawable.Drawable getDrawable();
+    method public int getOpacity();
+    method public void invalidateDrawable(android.graphics.drawable.Drawable);
+    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(android.graphics.drawable.Drawable);
+    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
+  }
+
   public class GradientDrawable extends android.graphics.drawable.Drawable {
     ctor public GradientDrawable();
     ctor public GradientDrawable(android.graphics.drawable.GradientDrawable.Orientation, int[]);
@@ -12263,17 +12277,9 @@
     enum_constant public static final android.graphics.drawable.GradientDrawable.Orientation TR_BL;
   }
 
-  public class InsetDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class InsetDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int);
     ctor public InsetDrawable(android.graphics.drawable.Drawable, int, int, int, int);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class LayerDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -12286,6 +12292,12 @@
     method public int getId(int);
     method public int getLayerGravity(int);
     method public int getLayerHeight(int);
+    method public int getLayerInsetBottom(int);
+    method public int getLayerInsetEnd(int);
+    method public int getLayerInsetLeft(int);
+    method public int getLayerInsetRight(int);
+    method public int getLayerInsetStart(int);
+    method public int getLayerInsetTop(int);
     method public int getLayerWidth(int);
     method public int getNumberOfLayers();
     method public int getOpacity();
@@ -12298,9 +12310,17 @@
     method public boolean setDrawableByLayerId(int, android.graphics.drawable.Drawable);
     method public void setId(int, int);
     method public void setLayerGravity(int, int);
+    method public void setLayerHeight(int, int);
     method public void setLayerInset(int, int, int, int, int);
+    method public void setLayerInsetBottom(int, int);
+    method public void setLayerInsetEnd(int, int);
+    method public void setLayerInsetLeft(int, int);
     method public void setLayerInsetRelative(int, int, int, int, int);
+    method public void setLayerInsetRight(int, int);
+    method public void setLayerInsetStart(int, int);
+    method public void setLayerInsetTop(int, int);
     method public void setLayerSize(int, int, int);
+    method public void setLayerWidth(int, int);
     method public void setOpacity(int);
     method public void setPaddingMode(int);
     method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
@@ -12353,41 +12373,24 @@
     field public static final int RADIUS_AUTO = -1; // 0xffffffff
   }
 
-  public class RotateDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class RotateDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public RotateDrawable();
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
     method public float getFromDegrees();
-    method public int getOpacity();
     method public float getPivotX();
     method public float getPivotY();
     method public float getToDegrees();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
     method public boolean isPivotXRelative();
     method public boolean isPivotYRelative();
-    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(android.graphics.drawable.Drawable);
     method public void setFromDegrees(float);
     method public void setPivotX(float);
     method public void setPivotXRelative(boolean);
     method public void setPivotY(float);
     method public void setPivotYRelative(boolean);
     method public void setToDegrees(float);
-    method public void unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
-  public class ScaleDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
+  public class ScaleDrawable extends android.graphics.drawable.DrawableWrapper {
     ctor public ScaleDrawable(android.graphics.drawable.Drawable, int, float, float);
-    method public void draw(android.graphics.Canvas);
-    method public android.graphics.drawable.Drawable getDrawable();
-    method public int getOpacity();
-    method public void invalidateDrawable(android.graphics.drawable.Drawable);
-    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 unscheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable);
   }
 
   public class ShapeDrawable extends android.graphics.drawable.Drawable {
@@ -15118,6 +15121,8 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_BEACON = 8; // 0x8
+    field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 64; // 0x40
+    field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
     field public static final int FLAG_HW_HOTWORD = 32; // 0x20
     field public static final int USAGE_ALARM = 4; // 0x4
@@ -30863,6 +30868,7 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 62081ee..a501fa7 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -138,6 +138,7 @@
                 "       am task lock <TASK_ID>\n" +
                 "       am task lock stop\n" +
                 "       am task resizeable <TASK_ID> [true|false]\n" +
+                "       am task resize <TASK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am get-config\n" +
                 "\n" +
                 "am start: start an Activity.  Options are:\n" +
@@ -249,11 +250,11 @@
                 "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." +
+                "am stack split: split <STACK_ID> into 2 stacks <v>ertically or <h>orizontally\n" +
+                "   starting the new stack with [INTENT] if specified. If [INTENT] isn't\n" +
+                "   specified and the current stack has more than one task, then the top task\n" +
+                "   of the current task will be moved to the new stack. Command will also force\n" +
+                "   all current tasks in both stacks to be resizeable.\n" +
                 "\n" +
                 "am stack list: list all of the activity stacks and their sizes.\n" +
                 "\n" +
@@ -265,6 +266,10 @@
                 "\n" +
                 "am task resizeable: change if <TASK_ID> is resizeable (true) or not (false).\n" +
                 "\n" +
+                "am task resize: makes sure <TASK_ID> is in a stack with the specified bounds.\n" +
+                "   Forces the task to be resizeable and creates a stack if no existing stack\n" +
+                "   has the specified bounds.\n" +
+                "\n" +
                 "am get-config: retrieve the configuration and any recent configurations\n" +
                 "  of the device\n" +
                 "\n" +
@@ -1742,33 +1747,14 @@
     private void runStackResize() throws Exception {
         String stackIdStr = nextArgRequired();
         int stackId = Integer.valueOf(stackIdStr);
-        String leftStr = nextArgRequired();
-        int left = Integer.valueOf(leftStr);
-        String topStr = nextArgRequired();
-        int top = Integer.valueOf(topStr);
-        String rightStr = nextArgRequired();
-        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);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
             return;
         }
 
         try {
-            mAm.resizeStack(stackId, new Rect(left, top, right, bottom));
+            mAm.resizeStack(stackId, bounds);
         } catch (RemoteException e) {
         }
     }
@@ -1857,6 +1843,8 @@
             runTaskLock();
         } else if (op.equals("resizeable")) {
             runTaskResizeable();
+        } else if (op.equals("resize")) {
+            runTaskResize();
         } else {
             showError("Error: unknown command '" + op + "'");
             return;
@@ -1890,6 +1878,20 @@
         }
     }
 
+    private void runTaskResize() throws Exception {
+        final String taskIdStr = nextArgRequired();
+        final int taskId = Integer.valueOf(taskIdStr);
+        final Rect bounds = getBounds();
+        if (bounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        try {
+            mAm.resizeTask(taskId, bounds);
+        } catch (RemoteException e) {
+        }
+    }
+
     private List<Configuration> getRecentConfigurations(int days) {
         IUsageStatsManager usm = IUsageStatsManager.Stub.asInterface(ServiceManager.getService(
                     Context.USAGE_STATS_SERVICE));
@@ -1986,4 +1988,32 @@
         }
         return fd;
     }
+
+    private Rect getBounds() {
+        String leftStr = nextArgRequired();
+        int left = Integer.valueOf(leftStr);
+        String topStr = nextArgRequired();
+        int top = Integer.valueOf(topStr);
+        String rightStr = nextArgRequired();
+        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 null;
+        }
+        if (top < 0) {
+            System.err.println("Error: bad top arg: " + topStr);
+            return null;
+        }
+        if (right <= 0) {
+            System.err.println("Error: bad right arg: " + rightStr);
+            return null;
+        }
+        if (bottom <= 0) {
+            System.err.println("Error: bad bottom arg: " + bottomStr);
+            return null;
+        }
+        return new Rect(left, top, right, bottom);
+    }
 }
diff --git a/cmds/bootanimation/AudioPlayer.cpp b/cmds/bootanimation/AudioPlayer.cpp
index 81fe5f8..2932130 100644
--- a/cmds/bootanimation/AudioPlayer.cpp
+++ b/cmds/bootanimation/AudioPlayer.cpp
@@ -305,7 +305,7 @@
 exit:
     if (pcm)
         pcm_close(pcm);
-    mCurrentFile->release();
+    delete mCurrentFile;
     mCurrentFile = NULL;
     return false;
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 1d4de22..bb25ec6 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -179,7 +179,7 @@
     // FileMap memory is never released until application exit.
     // Release it now as the texture is already loaded and the memory used for
     // the packed resource can be released.
-    frame.map->release();
+    delete frame.map;
 
     // ensure we can call getPixels(). No need to call unlock, since the
     // bitmap will go out of scope when we return from this method.
@@ -446,7 +446,7 @@
     }
 
     outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
-    entryMap->release();
+    delete entryMap;
     return true;
 }
 
diff --git a/cmds/idmap/scan.cpp b/cmds/idmap/scan.cpp
index bbe6eef..197e36b 100644
--- a/cmds/idmap/scan.cpp
+++ b/cmds/idmap/scan.cpp
@@ -147,20 +147,20 @@
         char *buf = new char[uncompLen];
         if (NULL == buf) {
             ALOGW("%s: failed to allocate %zd byte\n", __FUNCTION__, uncompLen);
-            dataMap->release();
+            delete dataMap;
             return -1;
         }
         StreamingZipInflater inflater(dataMap, uncompLen);
         if (inflater.read(buf, uncompLen) < 0) {
             ALOGW("%s: failed to inflate %zd byte\n", __FUNCTION__, uncompLen);
             delete[] buf;
-            dataMap->release();
+            delete dataMap;
             return -1;
         }
 
         int priority = parse_manifest(buf, uncompLen, target_package_name);
         delete[] buf;
-        dataMap->release();
+        delete dataMap;
         return priority;
     }
 }
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
index 26a61ae..5e88bca 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -117,6 +117,9 @@
                 cardRecord.parse(line, 0);
 
                 line = bufferedReader.readLine();
+                if (line == null) {
+                    break;
+                }
                 if (DEBUG) {
                     Slog.i(TAG, "  " + line);
                 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 005b1d9..bb307bb 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2313,6 +2313,15 @@
             return true;
         }
 
+        case RESIZE_TASK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            int taskId = data.readInt();
+            Rect r = Rect.CREATOR.createFromParcel(data);
+            resizeTask(taskId, r);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_TASK_DESCRIPTION_ICON_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             String filename = data.readString();
@@ -5438,6 +5447,20 @@
     }
 
     @Override
+    public void resizeTask(int taskId, Rect r) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(taskId);
+        r.writeToParcel(data, 0);
+        mRemote.transact(RESIZE_TASK_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 a8eb076..653b951 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1101,7 +1101,7 @@
         @Override
         public void dumpGfxInfo(FileDescriptor fd, String[] args) {
             dumpGraphicsInfo(fd);
-            WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
+            WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args);
         }
 
         private void dumpDatabaseInfo(FileDescriptor fd, String[] args) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0098d86..503657b 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -75,12 +75,12 @@
 import android.location.LocationManager;
 import android.media.AudioManager;
 import android.media.MediaRouter;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiManager;
 import android.media.projection.MediaProjectionManager;
 import android.media.session.MediaSessionManager;
 import android.media.tv.ITvInputManager;
 import android.media.tv.TvInputManager;
-import android.midi.IMidiManager;
-import android.midi.MidiManager;
 import android.net.ConnectivityManager;
 import android.net.IConnectivityManager;
 import android.net.EthernetManager;
@@ -2294,8 +2294,10 @@
         if (container != null) {
             compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
         }
-        if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) {
-            compatInfo = packageInfo.getCompatibilityInfo();
+        if (compatInfo == null) {
+            compatInfo = (displayId == Display.DEFAULT_DISPLAY)
+                    ? packageInfo.getCompatibilityInfo()
+                    : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
         }
         mDisplayAdjustments.setCompatibilityInfo(compatInfo);
         mDisplayAdjustments.setConfiguration(overrideConfiguration);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index c5f534c..bdcc312 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -1244,7 +1244,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
 
@@ -1310,7 +1310,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
-    public void onActivityCreated(Bundle savedInstanceState) {
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 1f5a1a0..a7e9413 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -464,6 +464,7 @@
     public void setTaskDescription(IBinder token, ActivityManager.TaskDescription values)
             throws RemoteException;
     public void setTaskResizeable(int taskId, boolean resizeable) throws RemoteException;
+    public void resizeTask(int taskId, Rect bounds) throws RemoteException;
     public Bitmap getTaskDescriptionIcon(String filename) throws RemoteException;
 
     public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts)
@@ -808,4 +809,5 @@
     int GET_FOCUSED_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+282;
     int SET_TASK_RESIZEABLE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+283;
     int REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+284;
+    int RESIZE_TASK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+285;
 }
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index c8e0031..21a3543 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -498,6 +499,7 @@
      * @return Return an IBinder through which clients can call on to the 
      *         service.
      */
+    @Nullable
     public abstract IBinder onBind(Intent intent);
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 318a314..d0ebdbd 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -111,9 +111,11 @@
      *
      * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
      *
-     * <p> When managed provisioning has completed, an intent of the type
-     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
-     * managed profile.
+     * <p> When managed provisioning has completed, broadcasts are sent to the application specified
+     * in the provisioning intent. The
+     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
+     * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
+     * the primary profile.
      *
      * <p> If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
@@ -332,6 +334,20 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
 
     /**
+     * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
+     * has completed successfully.
+     *
+     * <p>The broadcast is limited to the primary profile, to the app specified in the provisioning
+     * intent (@see #ACTION_PROVISION_MANAGED_PROFILE).
+     *
+     * <p>This intent will contain the extra {@link #EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} which
+     * corresponds to the account requested to be migrated at provisioning time, if any.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGED_PROFILE_PROVISIONED
+        = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+
+    /**
      * A boolean extra indicating whether device encryption is required as part of Device Owner
      * provisioning.
      *
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index eabe297..46ccc95 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2971,7 +2971,7 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a
-     * {@link android.midi.MidiManager} for accessing the MIDI service.
+     * {@link android.media.midi.MidiManager} for accessing the MIDI service.
      *
      * @see #getSystemService
      * @hide
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index cd32dae..1d16516 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -73,9 +73,7 @@
          * {@link #commit} or {@link #apply} are called.
          * 
          * @param key The name of the preference to modify.
-         * @param value The new value for the preference.  Supplying {@code null}
-         *    as the value is equivalent to calling {@link #remove(String)} with
-         *    this key.
+         * @param value The new value for the preference.
          * 
          * @return Returns a reference to the same Editor object, so you can
          * chain put calls together.
diff --git a/core/java/android/content/UndoManager.java b/core/java/android/content/UndoManager.java
index e9ec5a4..e3bc238 100644
--- a/core/java/android/content/UndoManager.java
+++ b/core/java/android/content/UndoManager.java
@@ -20,9 +20,9 @@
 import android.os.Parcelable;
 import android.os.ParcelableParcel;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 
 /**
  * Top-level class for managing and interacting with the global undo state for
@@ -54,7 +54,9 @@
  * @hide
  */
 public class UndoManager {
-    private final HashMap<String, UndoOwner> mOwners = new HashMap<String, UndoOwner>();
+    // The common case is a single undo owner (e.g. for a TextView), so default to that capacity.
+    private final ArrayMap<String, UndoOwner> mOwners =
+            new ArrayMap<String, UndoOwner>(1 /* capacity */);
     private final ArrayList<UndoState> mUndos = new ArrayList<UndoState>();
     private final ArrayList<UndoState> mRedos = new ArrayList<UndoState>();
     private int mUpdateCount;
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 60ff32c..87ec06a 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -424,17 +424,6 @@
             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
@@ -482,22 +471,6 @@
             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.
@@ -559,17 +532,6 @@
             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
@@ -676,6 +638,44 @@
             new Key<android.hardware.camera2.params.HighSpeedVideoConfiguration[]>("android.control.availableHighSpeedVideoConfigurations", android.hardware.camera2.params.HighSpeedVideoConfiguration[].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>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 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 edge enhancement modes for {@link CaptureRequest#EDGE_MODE android.edge.mode} that are supported by this camera
      * device.</p>
      * <p>Full-capability camera devices must always support OFF; all devices will list FAST.</p>
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index ffe30d4..7f901c8 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -380,8 +380,8 @@
      * <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>
+     * <li>android.tonemap.gamma</li>
+     * <li>android.tonemap.presetCurve</li>
      * </ul>
      * </li>
      * <li>
@@ -416,10 +416,8 @@
      * @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;
@@ -2113,26 +2111,22 @@
     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
+     * <p>Use the gamma value specified in 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>
+     * for applying the tonemapping curve specified by 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>
+     * 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>
+     * 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;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cd45cfb..4dadda2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -592,6 +592,86 @@
         }
     }
 
+    /**
+     * Optional detailed information that can go into a history step.  This is typically
+     * generated each time the battery level changes.
+     */
+    public final static class HistoryStepDetails {
+        // Time (in 1/100 second) spent in user space and the kernel since the last step.
+        public int userTime;
+        public int systemTime;
+
+        // Top three apps using CPU in the last step, with times in 1/100 second.
+        public int appCpuUid1;
+        public int appCpuUTime1;
+        public int appCpuSTime1;
+        public int appCpuUid2;
+        public int appCpuUTime2;
+        public int appCpuSTime2;
+        public int appCpuUid3;
+        public int appCpuUTime3;
+        public int appCpuSTime3;
+
+        // Information from /proc/stat
+        public int statUserTime;
+        public int statSystemTime;
+        public int statIOWaitTime;
+        public int statIrqTime;
+        public int statSoftIrqTime;
+        public int statIdlTime;
+
+        public HistoryStepDetails() {
+            clear();
+        }
+
+        public void clear() {
+            userTime = systemTime = 0;
+            appCpuUid1 = appCpuUid2 = appCpuUid3 = -1;
+            appCpuUTime1 = appCpuSTime1 = appCpuUTime2 = appCpuSTime2
+                    = appCpuUTime3 = appCpuSTime3 = 0;
+        }
+
+        public void writeToParcel(Parcel out) {
+            out.writeInt(userTime);
+            out.writeInt(systemTime);
+            out.writeInt(appCpuUid1);
+            out.writeInt(appCpuUTime1);
+            out.writeInt(appCpuSTime1);
+            out.writeInt(appCpuUid2);
+            out.writeInt(appCpuUTime2);
+            out.writeInt(appCpuSTime2);
+            out.writeInt(appCpuUid3);
+            out.writeInt(appCpuUTime3);
+            out.writeInt(appCpuSTime3);
+            out.writeInt(statUserTime);
+            out.writeInt(statSystemTime);
+            out.writeInt(statIOWaitTime);
+            out.writeInt(statIrqTime);
+            out.writeInt(statSoftIrqTime);
+            out.writeInt(statIdlTime);
+        }
+
+        public void readFromParcel(Parcel in) {
+            userTime = in.readInt();
+            systemTime = in.readInt();
+            appCpuUid1 = in.readInt();
+            appCpuUTime1 = in.readInt();
+            appCpuSTime1 = in.readInt();
+            appCpuUid2 = in.readInt();
+            appCpuUTime2 = in.readInt();
+            appCpuSTime2 = in.readInt();
+            appCpuUid3 = in.readInt();
+            appCpuUTime3 = in.readInt();
+            appCpuSTime3 = in.readInt();
+            statUserTime = in.readInt();
+            statSystemTime = in.readInt();
+            statIOWaitTime = in.readInt();
+            statIrqTime = in.readInt();
+            statSoftIrqTime = in.readInt();
+            statIdlTime = in.readInt();
+        }
+    }
+
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
 
@@ -687,6 +767,9 @@
         // Kernel wakeup reason at this point.
         public HistoryTag wakeReasonTag;
 
+        // Non-null when there is more detailed information at this step.
+        public HistoryStepDetails stepDetails;
+
         public static final int EVENT_FLAG_START = 0x8000;
         public static final int EVENT_FLAG_FINISH = 0x4000;
 
@@ -3692,10 +3775,115 @@
                     }
                 }
                 pw.println();
+                if (rec.stepDetails != null) {
+                    if (!checkin) {
+                        pw.print("                 Details: cpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print("u+");
+                        pw.print(rec.stepDetails.systemTime);
+                        pw.print("s");
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            pw.print(" (");
+                            printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                            pw.print(')');
+                        }
+                        pw.println();
+                        pw.print("                          /proc/stat=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(" usr, ");
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(" sys, ");
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(" io, ");
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(" irq, ");
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(" sirq, ");
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.print(" idle");
+                        int totalRun = rec.stepDetails.statUserTime + rec.stepDetails.statSystemTime
+                                + rec.stepDetails.statIOWaitTime + rec.stepDetails.statIrqTime
+                                + rec.stepDetails.statSoftIrqTime;
+                        int total = totalRun + rec.stepDetails.statIdlTime;
+                        if (total > 0) {
+                            pw.print(" (");
+                            float perc = ((float)totalRun) / ((float)total) * 100;
+                            pw.print(String.format("%.1f%%", perc));
+                            pw.print(" of ");
+                            StringBuilder sb = new StringBuilder(64);
+                            formatTimeMsNoSpace(sb, total*10);
+                            pw.print(sb);
+                            pw.print(")");
+                        }
+                        pw.println();
+                    } else {
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dcpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print(":");
+                        pw.print(rec.stepDetails.systemTime);
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                        }
+                        pw.println();
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dpst=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.println();
+                    }
+                }
                 oldState = rec.states;
                 oldState2 = rec.states2;
             }
         }
+
+        private void printStepCpuUidDetails(PrintWriter pw, int uid, int utime, int stime) {
+            UserHandle.formatUid(pw, uid);
+            pw.print("=");
+            pw.print(utime);
+            pw.print("u+");
+            pw.print(stime);
+            pw.print("s");
+        }
+
+        private void printStepCpuUidCheckinDetails(PrintWriter pw, int uid, int utime, int stime) {
+            pw.print('/');
+            pw.print(uid);
+            pw.print(":");
+            pw.print(utime);
+            pw.print(":");
+            pw.print(stime);
+        }
     }
 
     private void printSizeValue(PrintWriter pw, long size) {
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index eb86e7e..36fc4f9 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -680,6 +680,7 @@
             }
         }
 
+        /* TODO: Figure out issue with checks failing
         if (!TextUtils.isEmpty(bootimage)) {
             if (!Objects.equals(system, bootimage)) {
                 Slog.e(TAG, "Mismatched fingerprints; system reported " + system
@@ -703,6 +704,7 @@
                 return false;
             }
         }
+        */
 
         return true;
     }
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index d52dd30..e303f61 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -205,6 +205,20 @@
     public static final int DOZE_WAKE_LOCK = 0x00000040;
 
     /**
+     * Wake lock level: Keep the device awake enough to allow drawing to occur.
+     * <p>
+     * This is used by the window manager to allow applications to draw while the
+     * system is dozing.  It currently has no effect unless the power manager is in
+     * the dozing state.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * {@hide}
+     */
+    public static final int DRAW_WAKE_LOCK = 0x00000080;
+
+    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -489,6 +503,7 @@
             case FULL_WAKE_LOCK:
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
+            case DRAW_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java
index 9dbfd50..5c80ca6 100644
--- a/core/java/android/os/UEventObserver.java
+++ b/core/java/android/os/UEventObserver.java
@@ -22,13 +22,13 @@
 import java.util.HashMap;
 
 /**
- * UEventObserver is an abstract class that receives UEvent's from the kernel.<p>
+ * UEventObserver is an abstract class that receives UEvents from the kernel.<p>
  *
  * Subclass UEventObserver, implementing onUEvent(UEvent event), then call
  * startObserving() with a match string. The UEvent thread will then call your
  * onUEvent() method when a UEvent occurs that contains your match string.<p>
  *
- * Call stopObserving() to stop receiving UEvent's.<p>
+ * Call stopObserving() to stop receiving UEvents.<p>
  *
  * There is only one UEvent thread per process, even if that process has
  * multiple UEventObserver subclass instances. The UEvent thread starts when
@@ -78,7 +78,7 @@
     }
 
     /**
-     * Begin observation of UEvent's.<p>
+     * Begin observation of UEvents.<p>
      * This method will cause the UEvent thread to start if this is the first
      * invocation of startObserving in this process.<p>
      * Once called, the UEvent thread will call onUEvent() when an incoming
@@ -103,7 +103,7 @@
     }
 
     /**
-     * End observation of UEvent's.<p>
+     * End observation of UEvents.<p>
      * This process's UEvent thread will never call onUEvent() on this
      * UEventObserver after this call. Repeated calls have no effect.
      */
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 60ab05c..650f3b3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -116,6 +116,7 @@
 
     /**
      * Specifies if a user is disallowed from configuring bluetooth.
+     * This does <em>not</em> restrict the user from turning bluetooth on or off.
      * The default value is <code>false</code>.
      * <p/>This restriction has no effect in a managed profile.
      *
diff --git a/core/java/android/preference/PreferenceActivity.java b/core/java/android/preference/PreferenceActivity.java
index 0d80c0d..06666f4 100644
--- a/core/java/android/preference/PreferenceActivity.java
+++ b/core/java/android/preference/PreferenceActivity.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.annotation.XmlRes;
 import android.app.Fragment;
@@ -531,7 +532,7 @@
     }
 
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
         // Theming for the PreferenceActivity layout and for the Preference Header(s) layout
diff --git a/core/java/android/preference/PreferenceFragment.java b/core/java/android/preference/PreferenceFragment.java
index e95e6e2..29f9ca1 100644
--- a/core/java/android/preference/PreferenceFragment.java
+++ b/core/java/android/preference/PreferenceFragment.java
@@ -16,6 +16,7 @@
 
 package android.preference;
 
+import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Intent;
@@ -153,15 +154,15 @@
     }
 
     @Override
-    public void onCreate(Bundle savedInstanceState) {
+    public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         mPreferenceManager = new PreferenceManager(getActivity(), FIRST_REQUEST_CODE);
         mPreferenceManager.setFragment(this);
     }
 
     @Override
-    public View onCreateView(LayoutInflater inflater, ViewGroup container,
-            Bundle savedInstanceState) {
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            @Nullable Bundle savedInstanceState) {
 
         TypedArray a = getActivity().obtainStyledAttributes(null,
                 com.android.internal.R.styleable.PreferenceFragment,
@@ -177,7 +178,7 @@
     }
 
     @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
+    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
 
         if (mHavePrefs) {
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index c3dd4ce..30da0e7 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -174,6 +175,11 @@
             }
             if (mRingtone != null) {
                 try {
+                    mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
+                            .getAudioAttributes())
+                            .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
+                                    AudioAttributes.FLAG_BYPASS_MUTE)
+                            .build());
                     mRingtone.play();
                 } catch (Throwable e) {
                     Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index f023df7..266922d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -33,7 +33,9 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.DataUsageFeedback;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
@@ -336,22 +338,33 @@
         // that was encoded into call log databases.
 
         /**
-         * The component name of the account in string form.
+         * The component name of the account used to place or receive the call; in string form.
          * <P>Type: TEXT</P>
          */
         public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
 
         /**
-         * The identifier of a account that is unique to a specified component.
+         * The identifier for the account used to place or receive the call.
          * <P>Type: TEXT</P>
          */
         public static final String PHONE_ACCOUNT_ID = "subscription_id";
 
         /**
-         * The identifier of a account that is unique to a specified component. Equivalent value
-         * to {@link #PHONE_ACCOUNT_ID}. For ContactsProvider internal use only.
+         * The address associated with the account used to place or receive the call; in string
+         * form. For SIM-based calls, this is the user's own phone number.
+         * <P>Type: TEXT</P>
+         *
+         * @hide
+         */
+        public static final String PHONE_ACCOUNT_ADDRESS = "phone_account_address";
+
+        /**
+         * The subscription ID used to place this call.  This is no longer used and has been
+         * replaced with PHONE_ACCOUNT_COMPONENT_NAME/PHONE_ACCOUNT_ID.
+         * For ContactsProvider internal use only.
          * <P>Type: INTEGER</P>
          *
+         * @Deprecated
          * @hide
          */
         public static final String SUB_ID = "sub_id";
@@ -422,6 +435,19 @@
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
 
+            TelecomManager tm = null;
+            try {
+                tm = TelecomManager.from(context);
+            } catch (UnsupportedOperationException e) {}
+
+            String accountAddress = null;
+            if (tm != null && accountHandle != null) {
+                PhoneAccount account = tm.getPhoneAccount(accountHandle);
+                if (account != null) {
+                    accountAddress = account.getSubscriptionAddress().getSchemeSpecificPart();
+                }
+            }
+
             // Remap network specified number presentation types
             // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
             // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
@@ -463,6 +489,7 @@
             }
             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
             values.put(PHONE_ACCOUNT_ID, accountId);
+            values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
             values.put(NEW, Integer.valueOf(1));
 
             if (callType == MISSED_TYPE) {
diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl
index bf51ed1..ac6bbb7 100644
--- a/core/java/android/security/IKeystoreService.aidl
+++ b/core/java/android/security/IKeystoreService.aidl
@@ -16,6 +16,10 @@
 
 package android.security;
 
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.OperationResult;
 import android.security.KeystoreArguments;
 
 /**
@@ -52,4 +56,19 @@
     int reset_uid(int uid);
     int sync_uid(int sourceUid, int targetUid);
     int password_uid(String password, int uid);
+
+    // Keymaster 0.4 methods
+    int addRngEntropy(in byte[] data);
+    int generateKey(String alias, in KeymasterArguments arguments, int uid, int flags,
+        out KeyCharacteristics characteristics);
+    int getKeyCharacteristics(String alias, in byte[] clientId,
+        in byte[] appId, out KeyCharacteristics characteristics);
+    int importKey(String alias, in KeymasterArguments arguments, int format,
+        in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics);
+    ExportResult exportKey(String alias, int format, in byte[] clientId, in byte[] appId);
+    OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable,
+        in KeymasterArguments params, out KeymasterArguments operationParams);
+    OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input);
+    OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature);
+    int abort(IBinder handle);
 }
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/core/java/android/security/keymaster/ExportResult.aidl
similarity index 80%
copy from core/java/android/midi/MidiDeviceInfo.aidl
copy to core/java/android/security/keymaster/ExportResult.aidl
index 59be059..f522355 100644
--- a/core/java/android/midi/MidiDeviceInfo.aidl
+++ b/core/java/android/security/keymaster/ExportResult.aidl
@@ -1,5 +1,5 @@
-/*
- * 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,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.security.keymaster;
 
-parcelable MidiDeviceInfo;
+/* @hide */
+parcelable ExportResult;
diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java
new file mode 100644
index 0000000..bb44c03
--- /dev/null
+++ b/core/java/android/security/keymaster/ExportResult.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Class for handling parceling the return values from keymaster's export operation.
+ * @hide
+ */
+public class ExportResult implements Parcelable {
+    public final int resultCode;
+    public final byte[] exportData;
+
+    public static final Parcelable.Creator<ExportResult> CREATOR = new
+            Parcelable.Creator<ExportResult>() {
+                public ExportResult createFromParcel(Parcel in) {
+                    return new ExportResult(in);
+                }
+
+                public ExportResult[] newArray(int length) {
+                    return new ExportResult[length];
+                }
+            };
+
+    protected ExportResult(Parcel in) {
+        resultCode = in.readInt();
+        exportData = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(resultCode);
+        out.writeByteArray(exportData);
+    }
+};
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl
similarity index 79%
copy from core/java/android/midi/MidiDeviceInfo.aidl
copy to core/java/android/security/keymaster/KeyCharacteristics.aidl
index 59be059..15014b1 100644
--- a/core/java/android/midi/MidiDeviceInfo.aidl
+++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl
@@ -1,5 +1,5 @@
-/*
- * 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,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.security.keymaster;
 
-parcelable MidiDeviceInfo;
+/* @hide */
+parcelable KeyCharacteristics;
diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java
new file mode 100644
index 0000000..b803a1b
--- /dev/null
+++ b/core/java/android/security/keymaster/KeyCharacteristics.java
@@ -0,0 +1,63 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class KeyCharacteristics implements Parcelable {
+    public KeymasterArguments swEnforced;
+    public KeymasterArguments hwEnforced;
+
+    public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new
+            Parcelable.Creator<KeyCharacteristics>() {
+                public KeyCharacteristics createFromParcel(Parcel in) {
+                    return new KeyCharacteristics(in);
+                }
+
+                public KeyCharacteristics[] newArray(int length) {
+                    return new KeyCharacteristics[length];
+                }
+            };
+
+    public KeyCharacteristics() {}
+
+    protected KeyCharacteristics(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        swEnforced.writeToParcel(out, flags);
+        hwEnforced.writeToParcel(out, flags);
+    }
+
+    public void readFromParcel(Parcel in) {
+        swEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
+        hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in);
+    }
+}
+
diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java
new file mode 100644
index 0000000..9a1c894
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterArgument.java
@@ -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.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelFormatException;
+
+/**
+ * Base class for the Java side of a Keymaster tagged argument.
+ * <p>
+ * Serialization code for this and subclasses must be kept in sync with system/security/keystore
+ * and with hardware/libhardware/include/hardware/keymaster_defs.h
+ * @hide
+ */
+abstract class KeymasterArgument implements Parcelable {
+    public final int tag;
+
+    public static final Parcelable.Creator<KeymasterArgument> CREATOR = new
+            Parcelable.Creator<KeymasterArgument>() {
+                public KeymasterArgument createFromParcel(Parcel in) {
+                    final int pos = in.dataPosition();
+                    final int tag = in.readInt();
+                    switch (KeymasterDefs.getTagType(tag)) {
+                        case KeymasterDefs.KM_ENUM:
+                        case KeymasterDefs.KM_ENUM_REP:
+                        case KeymasterDefs.KM_INT:
+                        case KeymasterDefs.KM_INT_REP:
+                            return new KeymasterIntArgument(tag, in);
+                        case KeymasterDefs.KM_LONG:
+                            return new KeymasterLongArgument(tag, in);
+                        case KeymasterDefs.KM_DATE:
+                            return new KeymasterDateArgument(tag, in);
+                        case KeymasterDefs.KM_BYTES:
+                        case KeymasterDefs.KM_BIGNUM:
+                            return new KeymasterBlobArgument(tag, in);
+                        case KeymasterDefs.KM_BOOL:
+                            return new KeymasterBooleanArgument(tag, in);
+                        default:
+                            throw new ParcelFormatException("Bad tag: " + tag + " at " + pos);
+                    }
+                }
+                public KeymasterArgument[] newArray(int size) {
+                    return new KeymasterArgument[size];
+                }
+            };
+
+    protected KeymasterArgument(int tag) {
+        this.tag = tag;
+    }
+
+    /**
+     * Writes the value of this argument, if any, to the provided parcel.
+     */
+    public abstract void writeValue(Parcel out);
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(tag);
+        writeValue(out);
+    }
+}
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl
similarity index 79%
copy from core/java/android/midi/MidiDeviceInfo.aidl
copy to core/java/android/security/keymaster/KeymasterArguments.aidl
index 59be059..7aef5a6 100644
--- a/core/java/android/midi/MidiDeviceInfo.aidl
+++ b/core/java/android/security/keymaster/KeymasterArguments.aidl
@@ -1,5 +1,5 @@
-/*
- * 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,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.security.keymaster;
 
-parcelable MidiDeviceInfo;
+/* @hide */
+parcelable KeymasterArguments;
diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java
new file mode 100644
index 0000000..b5fd4bd
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterArguments.java
@@ -0,0 +1,186 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Utility class for the java side of user specified Keymaster arguments.
+ * <p>
+ * Serialization code for this and subclasses must be kept in sync with system/security/keystore
+ * @hide
+ */
+public class KeymasterArguments implements Parcelable {
+    List<KeymasterArgument> mArguments;
+
+    public static final Parcelable.Creator<KeymasterArguments> CREATOR = new
+            Parcelable.Creator<KeymasterArguments>() {
+                public KeymasterArguments createFromParcel(Parcel in) {
+                    return new KeymasterArguments(in);
+                }
+                public KeymasterArguments[] newArray(int size) {
+                    return new KeymasterArguments[size];
+                }
+            };
+
+    public KeymasterArguments() {
+        mArguments = new ArrayList<KeymasterArgument>();
+    }
+
+    private KeymasterArguments(Parcel in) {
+        mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR);
+    }
+
+    public void addInt(int tag, int value) {
+        mArguments.add(new KeymasterIntArgument(tag, value));
+    }
+
+    public void addBoolean(int tag) {
+        mArguments.add(new KeymasterBooleanArgument(tag));
+    }
+
+    public void addLong(int tag, long value) {
+        mArguments.add(new KeymasterLongArgument(tag, value));
+    }
+
+    public void addBlob(int tag, byte[] value) {
+        mArguments.add(new KeymasterBlobArgument(tag, value));
+    }
+
+    public void addDate(int tag, Date value) {
+        mArguments.add(new KeymasterDateArgument(tag, value));
+    }
+
+    private KeymasterArgument getArgumentByTag(int tag) {
+        for (KeymasterArgument arg : mArguments) {
+            if (arg.tag == tag) {
+                return arg;
+            }
+        }
+        return null;
+    }
+
+    public boolean containsTag(int tag) {
+        return getArgumentByTag(tag) != null;
+    }
+
+    public int getInt(int tag, int defaultValue) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_ENUM:
+            case KeymasterDefs.KM_INT:
+                break; // Accepted types
+            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_ENUM_REP:
+                throw new IllegalArgumentException("Repeatable tags must use getInts: " + tag);
+            default:
+                throw new IllegalArgumentException("Tag is not an int type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterIntArgument) arg).value;
+    }
+
+    public long getLong(int tag, long defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG) {
+            throw new IllegalArgumentException("Tag is not a long type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterLongArgument) arg).value;
+    }
+
+    public Date getDate(int tag, Date defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) {
+            throw new IllegalArgumentException("Tag is not a date type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterDateArgument) arg).date;
+    }
+
+    public boolean getBoolean(int tag, boolean defaultValue) {
+        if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) {
+            throw new IllegalArgumentException("Tag is not a boolean type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return true;
+    }
+
+    public byte[] getBlob(int tag, byte[] defaultValue) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_BYTES:
+            case KeymasterDefs.KM_BIGNUM:
+                break; // Allowed types.
+            default:
+                throw new IllegalArgumentException("Tag is not a blob type: " + tag);
+        }
+        KeymasterArgument arg = getArgumentByTag(tag);
+        if (arg == null) {
+            return defaultValue;
+        }
+        return ((KeymasterBlobArgument) arg).blob;
+    }
+
+    public List<Integer> getInts(int tag) {
+        switch (KeymasterDefs.getTagType(tag)) {
+            case KeymasterDefs.KM_INT_REP:
+            case KeymasterDefs.KM_ENUM_REP:
+                break; // Allowed types.
+            default:
+                throw new IllegalArgumentException("Tag is not a repeating type: " + tag);
+        }
+        List<Integer> values = new ArrayList<Integer>();
+        for (KeymasterArgument arg : mArguments) {
+            if (arg.tag == tag) {
+                values.add(((KeymasterIntArgument) arg).value);
+            }
+        }
+        return values;
+    }
+
+    public int size() {
+        return mArguments.size();
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeTypedList(mArguments);
+    }
+
+    public void readFromParcel(Parcel in) {
+        in.readTypedList(mArguments, KeymasterArgument.CREATOR);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java
new file mode 100644
index 0000000..27f1153
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+class KeymasterBlobArgument extends KeymasterArgument {
+    public final byte[] blob;
+
+    public KeymasterBlobArgument(int tag, byte[] blob) {
+        super(tag);
+        this.blob = blob;
+    }
+
+    public KeymasterBlobArgument(int tag, Parcel in) {
+        super(tag);
+        blob = in.createByteArray();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeByteArray(blob);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
new file mode 100644
index 0000000..8e17db4
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+class KeymasterBooleanArgument extends KeymasterArgument {
+
+    // Boolean arguments are always true if they exist and false if they don't.
+    public final boolean value = true;
+
+    public KeymasterBooleanArgument(int tag) {
+        super(tag);
+    }
+
+    public KeymasterBooleanArgument(int tag, Parcel in) {
+        super(tag);
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        // Do nothing, value is implicit.
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java
new file mode 100644
index 0000000..e8f4055
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterDateArgument.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+
+/**
+ * @hide
+ */
+class KeymasterDateArgument extends KeymasterArgument {
+    public final Date date;
+
+    public KeymasterDateArgument(int tag, Date date) {
+        super(tag);
+        this.date = date;
+    }
+
+    public KeymasterDateArgument(int tag, Parcel in) {
+        super(tag);
+        date = new Date(in.readLong());
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeLong(date.getTime());
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
new file mode 100644
index 0000000..88cad79
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -0,0 +1,227 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+/**
+ * Class tracking all the keymaster enum values needed for the binder API to keystore.
+ * This must be kept in sync with hardware/libhardware/include/hardware/keymaster_defs.h
+ * See keymaster_defs.h for detailed descriptions of each constant.
+ * @hide
+ */
+public final class KeymasterDefs {
+
+    private KeymasterDefs() {}
+
+    // Tag types.
+    public static final int KM_INVALID = 0 << 28;
+    public static final int KM_ENUM = 1 << 28;
+    public static final int KM_ENUM_REP = 2 << 28;
+    public static final int KM_INT = 3 << 28;
+    public static final int KM_INT_REP = 4 << 28;
+    public static final int KM_LONG = 5 << 28;
+    public static final int KM_DATE = 6 << 28;
+    public static final int KM_BOOL = 7 << 28;
+    public static final int KM_BIGNUM = 8 << 28;
+    public static final int KM_BYTES = 9 << 28;
+
+    // Tag values.
+    public static final int KM_TAG_INVALID = KM_INVALID | 0;
+    public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1;
+    public static final int KM_TAG_ALGORITHM = KM_ENUM | 2;
+    public static final int KM_TAG_KEY_SIZE = KM_INT | 3;
+    public static final int KM_TAG_BLOCK_MODE = KM_ENUM | 4;
+    public static final int KM_TAG_DIGEST = KM_ENUM | 5;
+    public static final int KM_TAG_MAC_LENGTH = KM_INT | 6;
+    public static final int KM_TAG_PADDING = KM_ENUM | 7;
+    public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 8;
+    public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 9;
+
+    public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
+    public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
+    public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705;
+
+    public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200;
+    public static final int KM_TAG_DSA_GENERATOR = KM_BIGNUM | 201;
+    public static final int KM_TAG_DSA_P = KM_BIGNUM | 202;
+    public static final int KM_TAG_DSA_Q = KM_BIGNUM | 203;
+    public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400;
+    public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401;
+    public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402;
+    public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_INT | 403;
+    public static final int KM_TAG_MAX_USES_PER_BOOT = KM_INT | 404;
+
+    public static final int KM_TAG_ALL_USERS = KM_BOOL | 500;
+    public static final int KM_TAG_USER_ID = KM_INT | 501;
+    public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 502;
+    public static final int KM_TAG_USER_AUTH_ID = KM_INT_REP | 503;
+    public static final int KM_TAG_AUTH_TIMEOUT = KM_INT | 504;
+
+    public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
+    public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
+
+    public static final int KM_TAG_APPLICATION_DATA = KM_BYTES | 700;
+    public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701;
+    public static final int KM_TAG_ORIGIN = KM_ENUM | 702;
+    public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703;
+    public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704;
+
+    public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000;
+    public static final int KM_TAG_NONCE = KM_BYTES | 1001;
+    public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002;
+
+    // Algorithm values.
+    public static final int KM_ALGORITHM_RSA = 1;
+    public static final int KM_ALGORITHM_DSA = 2;
+    public static final int KM_ALGORITHM_ECDSA = 3;
+    public static final int KM_ALGORITHM_ECIES = 4;
+    public static final int KM_ALGORITHM_AES = 32;
+    public static final int KM_ALGORITHM_3DES = 33;
+    public static final int KM_ALGORITHM_SKIPJACK = 34;
+    public static final int KM_ALGORITHM_MARS = 48;
+    public static final int KM_ALGORITHM_RC6 = 49;
+    public static final int KM_ALGORITHM_SERPENT = 50;
+    public static final int KM_ALGORITHM_TWOFISH = 51;
+    public static final int KM_ALGORITHM_IDEA = 52;
+    public static final int KM_ALGORITHM_RC5 = 53;
+    public static final int KM_ALGORITHM_CAST5 = 54;
+    public static final int KM_ALGORITHM_BLOWFISH = 55;
+    public static final int KM_ALGORITHM_RC4 = 64;
+    public static final int KM_ALGORITHM_CHACHA20 = 65;
+    public static final int KM_ALGORITHM_HMAC = 128;
+
+    // Block modes.
+    public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1;
+    public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED;
+    public static final int KM_MODE_CBC = 2;
+    public static final int KM_MODE_CBC_CTS = 3;
+    public static final int KM_MODE_CTR = 4;
+    public static final int KM_MODE_OFB = 5;
+    public static final int KM_MODE_CFB = 6;
+    public static final int KM_MODE_XTS = 7;
+    public static final int KM_MODE_FIRST_AUTHENTICATED = 32;
+    public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED;
+    public static final int KM_MODE_OCB = 33;
+    public static final int KM_MODE_CCM = 34;
+    public static final int KM_MODE_FIRST_MAC = 128;
+    public static final int KM_MODE_CMAC = KM_MODE_FIRST_MAC;
+    public static final int KM_MODE_POLY1305 = 129;
+
+    // Padding modes.
+    public static final int KM_PAD_NONE = 1;
+    public static final int KM_PAD_RSA_OAEP = 2;
+    public static final int KM_PAD_RSA_PSS = 3;
+    public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4;
+    public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5;
+    public static final int KM_PAD_ANSI_X923 = 32;
+    public static final int KM_PAD_ISO_10126 = 33;
+    public static final int KM_PAD_ZERO = 64;
+    public static final int KM_PAD_PKCS7 = 65;
+    public static final int KM_PAD_ISO_7816_4 = 66;
+
+    // Digest modes.
+    public static final int KM_DIGEST_NONE = 0;
+    public static final int KM_DIGEST_MD5 = 1;
+    public static final int KM_DIGEST_SHA1 = 2;
+    public static final int KM_DIGEST_SHA_2_224 = 3;
+    public static final int KM_DIGEST_SHA_2_256 = 4;
+    public static final int KM_DIGEST_SHA_2_384 = 5;
+    public static final int KM_DIGEST_SHA_2_512 = 6;
+    public static final int KM_DIGEST_SHA_3_256 = 7;
+    public static final int KM_DIGEST_SHA_3_384 = 8;
+    public static final int KM_DIGEST_SHA_3_512 = 9;
+
+    // Key origins.
+    public static final int KM_ORIGIN_HARDWARE = 0;
+    public static final int KM_ORIGIN_SOFTWARE = 1;
+    public static final int KM_ORIGIN_IMPORTED = 2;
+
+    // Key usability requirements.
+    public static final int KM_BLOB_STANDALONE = 0;
+    public static final int KM_BLOB_REQUIRES_FILE_SYSTEM = 1;
+
+    // Operation Purposes.
+    public static final int KM_PURPOSE_ENCRYPT = 0;
+    public static final int KM_PURPOSE_DECRYPT = 1;
+    public static final int KM_PURPOSE_SIGN = 2;
+    public static final int KM_PURPOSE_VERIFY = 3;
+
+    // Key formats.
+    public static final int KM_KEY_FORMAT_X509 = 0;
+    public static final int KM_KEY_FORMAT_PKCS8 = 1;
+    public static final int KM_KEY_FORMAT_PKCS12 = 2;
+    public static final int KM_KEY_FORMAT_RAW = 3;
+
+    // Error codes.
+    public static final int KM_ERROR_OK = 0;
+    public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1;
+    public static final int KM_ERROR_UNSUPPORTED_PURPOSE = -2;
+    public static final int KM_ERROR_INCOMPATIBLE_PURPOSE = -3;
+    public static final int KM_ERROR_UNSUPPORTED_ALGORITHM = -4;
+    public static final int KM_ERROR_INCOMPATIBLE_ALGORITHM = -5;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6;
+    public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7;
+    public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8;
+    public static final int KM_ERROR_UNSUPPORTED_TAG_LENGTH = -9;
+    public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10;
+    public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11;
+    public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12;
+    public static final int KM_ERROR_INCOMPATIBLE_DIGEST = -13;
+    public static final int KM_ERROR_INVALID_EXPIRATION_TIME = -14;
+    public static final int KM_ERROR_INVALID_USER_ID = -15;
+    public static final int KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT = -16;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_FORMAT = -17;
+    public static final int KM_ERROR_INCOMPATIBLE_KEY_FORMAT = -18;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19;
+    public static final int KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20;
+    public static final int KM_ERROR_INVALID_INPUT_LENGTH = -21;
+    public static final int KM_ERROR_KEY_EXPORT_OPTIONS_INVALID = -22;
+    public static final int KM_ERROR_DELEGATION_NOT_ALLOWED = -23;
+    public static final int KM_ERROR_KEY_NOT_YET_VALID = -24;
+    public static final int KM_ERROR_KEY_EXPIRED = -25;
+    public static final int KM_ERROR_KEY_USER_NOT_AUTHENTICATED = -26;
+    public static final int KM_ERROR_OUTPUT_PARAMETER_NULL = -27;
+    public static final int KM_ERROR_INVALID_OPERATION_HANDLE = -28;
+    public static final int KM_ERROR_INSUFFICIENT_BUFFER_SPACE = -29;
+    public static final int KM_ERROR_VERIFICATION_FAILED = -30;
+    public static final int KM_ERROR_TOO_MANY_OPERATIONS = -31;
+    public static final int KM_ERROR_UNEXPECTED_NULL_POINTER = -32;
+    public static final int KM_ERROR_INVALID_KEY_BLOB = -33;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED = -34;
+    public static final int KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED = -35;
+    public static final int KM_ERROR_IMPORTED_KEY_NOT_SIGNED = -36;
+    public static final int KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED = -37;
+    public static final int KM_ERROR_INVALID_ARGUMENT = -38;
+    public static final int KM_ERROR_UNSUPPORTED_TAG = -39;
+    public static final int KM_ERROR_INVALID_TAG = -40;
+    public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41;
+    public static final int KM_ERROR_INVALID_RESCOPING = -42;
+    public static final int KM_ERROR_INVALID_DSA_PARAMS = -43;
+    public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44;
+    public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45;
+    public static final int KM_ERROR_OPERATION_CANCELLED = -46;
+    public static final int KM_ERROR_CONCURRENT_ACCESS_CONFLICT = -47;
+    public static final int KM_ERROR_SECURE_HW_BUSY = -48;
+    public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49;
+    public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50;
+    public static final int KM_ERROR_UNIMPLEMENTED = -100;
+    public static final int KM_ERROR_VERSION_MISMATCH = -101;
+    public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
+
+    public static int getTagType(int tag) {
+        return tag & (0xF << 28);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java
new file mode 100644
index 0000000..71797ae
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterIntArgument.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+class KeymasterIntArgument extends KeymasterArgument {
+    public final int value;
+
+    public KeymasterIntArgument(int tag, int value) {
+        super(tag);
+        this.value = value;
+    }
+
+    public KeymasterIntArgument(int tag, Parcel in) {
+        super(tag);
+        value = in.readInt();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeInt(value);
+    }
+}
diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java
new file mode 100644
index 0000000..781b1ab
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterLongArgument.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * @hide
+ */
+class KeymasterLongArgument extends KeymasterArgument {
+    public final long value;
+
+    public KeymasterLongArgument(int tag, long value) {
+        super(tag);
+        this.value = value;
+    }
+
+    public KeymasterLongArgument(int tag, Parcel in) {
+        super(tag);
+        value = in.readLong();
+    }
+
+    @Override
+    public void writeValue(Parcel out) {
+        out.writeLong(value);
+    }
+}
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/core/java/android/security/keymaster/OperationResult.aidl
similarity index 80%
copy from core/java/android/midi/MidiDeviceInfo.aidl
copy to core/java/android/security/keymaster/OperationResult.aidl
index 59be059..699e8d0 100644
--- a/core/java/android/midi/MidiDeviceInfo.aidl
+++ b/core/java/android/security/keymaster/OperationResult.aidl
@@ -1,5 +1,5 @@
-/*
- * 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,6 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.security.keymaster;
 
-parcelable MidiDeviceInfo;
+/* @hide */
+parcelable OperationResult;
diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java
new file mode 100644
index 0000000..ad54c96
--- /dev/null
+++ b/core/java/android/security/keymaster/OperationResult.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keymaster;
+
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * Class for handling the parceling of return values from keymaster crypto operations
+ * (begin/update/finish).
+ * @hide
+ */
+public class OperationResult implements Parcelable {
+    public final int resultCode;
+    public final IBinder token;
+    public final int inputConsumed;
+    public final byte[] output;
+
+    public static final Parcelable.Creator<OperationResult> CREATOR = new
+            Parcelable.Creator<OperationResult>() {
+                public OperationResult createFromParcel(Parcel in) {
+                    return new OperationResult(in);
+                }
+
+                public OperationResult[] newArray(int length) {
+                    return new OperationResult[length];
+                }
+            };
+
+    protected OperationResult(Parcel in) {
+        resultCode = in.readInt();
+        token = in.readStrongBinder();
+        inputConsumed = in.readInt();
+        output = in.createByteArray();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(resultCode);
+        out.writeStrongBinder(token);
+        out.writeInt(inputConsumed);
+        out.writeByteArray(output);
+    }
+}
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 48bb5dd..1bb35f6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -457,7 +458,7 @@
      * @param str the string to be examined
      * @return true if str is null or zero length
      */
-    public static boolean isEmpty(CharSequence str) {
+    public static boolean isEmpty(@Nullable CharSequence str) {
         if (str == null || str.length() == 0)
             return true;
         else
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f41afcf..c8149d9 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -141,6 +141,19 @@
     private long mFrameIntervalNanos;
 
     /**
+     * Contains information about the current frame for jank-tracking,
+     * mainly timings of key events along with a bit of metadata about
+     * view tree state
+     *
+     * TODO: Is there a better home for this? Currently Choreographer
+     * is the only one with CALLBACK_ANIMATION start time, hence why this
+     * resides here.
+     *
+     * @hide
+     */
+    FrameInfo mFrameInfo = new FrameInfo();
+
+    /**
      * Callback type: Input callback.  Runs first.
      * @hide
      */
@@ -513,6 +526,7 @@
                 return; // no work to do
             }
 
+            long intendedFrameTimeNanos = frameTimeNanos;
             startNanos = System.nanoTime();
             final long jitterNanos = startNanos - frameTimeNanos;
             if (jitterNanos >= mFrameIntervalNanos) {
@@ -541,12 +555,18 @@
                 return;
             }
 
+            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
             mFrameScheduled = false;
             mLastFrameTimeNanos = frameTimeNanos;
         }
 
+        mFrameInfo.markInputHandlingStart();
         doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+
+        mFrameInfo.markAnimationsStart();
         doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+
+        mFrameInfo.markPerformTraversalsStart();
         doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
 
         if (DEBUG) {
diff --git a/core/java/android/view/FrameInfo.java b/core/java/android/view/FrameInfo.java
new file mode 100644
index 0000000..c79547c
--- /dev/null
+++ b/core/java/android/view/FrameInfo.java
@@ -0,0 +1,118 @@
+/*
+ * 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;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that contains all the timing information for the current frame. This
+ * is used in conjunction with the hardware renderer to provide
+ * continous-monitoring jank events
+ *
+ * All times in nanoseconds from CLOCK_MONOTONIC/System.nanoTime()
+ *
+ * To minimize overhead from System.nanoTime() calls we infer durations of
+ * things by knowing the ordering of the events. For example, to know how
+ * long layout & measure took it's displayListRecordStart - performTraversalsStart.
+ *
+ * These constants must be kept in sync with FrameInfo.h in libhwui and are
+ * used for indexing into AttachInfo's mFrameInfo long[], which is intended
+ * to be quick to pass down to native via JNI, hence a pre-packed format
+ *
+ * @hide
+ */
+final class FrameInfo {
+
+    long[] mFrameInfo = new long[9];
+
+    // Various flags set to provide extra metadata about the current frame
+    private static final int FLAGS = 0;
+
+    // Is this the first-draw following a window layout?
+    public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_WINDOW_LAYOUT_CHANGED })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FrameInfoFlags {}
+
+    // The intended vsync time, unadjusted by jitter
+    private static final int INTENDED_VSYNC = 1;
+
+    // Jitter-adjusted vsync time, this is what was used as input into the
+    // animation & drawing system
+    private static final int VSYNC = 2;
+
+    // The time of the oldest input event
+    private static final int OLDEST_INPUT_EVENT = 3;
+
+    // The time of the newest input event
+    private static final int NEWEST_INPUT_EVENT = 4;
+
+    // When input event handling started
+    private static final int HANDLE_INPUT_START = 5;
+
+    // When animation evaluations started
+    private static final int ANIMATION_START = 6;
+
+    // When ViewRootImpl#performTraversals() started
+    private static final int PERFORM_TRAVERSALS_START = 7;
+
+    // When View:draw() started
+    private static final int DRAW_START = 8;
+
+    public void setVsync(long intendedVsync, long usedVsync) {
+        mFrameInfo[INTENDED_VSYNC] = intendedVsync;
+        mFrameInfo[VSYNC] = usedVsync;
+        mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
+        mFrameInfo[NEWEST_INPUT_EVENT] = 0;
+        mFrameInfo[FLAGS] = 0;
+    }
+
+    public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
+        if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
+            mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
+        }
+        if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
+            mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
+        }
+    }
+
+    public void markInputHandlingStart() {
+        mFrameInfo[HANDLE_INPUT_START] = System.nanoTime();
+    }
+
+    public void markAnimationsStart() {
+        mFrameInfo[ANIMATION_START] = System.nanoTime();
+    }
+
+    public void markPerformTraversalsStart() {
+        mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
+    }
+
+    public void markDrawStart() {
+        mFrameInfo[DRAW_START] = System.nanoTime();
+    }
+
+    public void addFlags(@FrameInfoFlags long flags) {
+        mFrameInfo[FLAGS] |= flags;
+    }
+
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c5c3f83..aa61885 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -278,7 +278,7 @@
     /**
      * Outputs extra debugging information in the specified file descriptor.
      */
-    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd);
+    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args);
 
     /**
      * Loads system properties used by the renderer. This method is invoked
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index d08ab46..fc0148f 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -194,4 +194,19 @@
     void onRectangleOnScreenRequested(IBinder token, in Rect rectangle);
 
     IWindowId getWindowId(IBinder window);
+
+    /**
+     * When the system is dozing in a low-power partially suspended state, pokes a short
+     * lived wake lock and ensures that the display is ready to accept the next frame
+     * of content drawn in the window.
+     *
+     * This mechanism is bound to the window rather than to the display manager or the
+     * power manager so that the system can ensure that the window is actually visible
+     * and prevent runaway applications from draining the battery.  This is similar to how
+     * FLAG_KEEP_SCREEN_ON works.
+     *
+     * This method is synchronous because it may need to acquire a wake lock before returning.
+     * The assumption is that this method will be called rather infrequently.
+     */
+    void pokeDrawLock(IBinder window);
 }
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index ca8a68a..54a0025 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -25,7 +25,9 @@
 import android.app.ActivityManagerNative;
 import android.app.SearchManager;
 import android.os.UserHandle;
+
 import com.android.internal.R;
+import com.android.internal.view.ActionModeWrapper;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -2689,72 +2691,17 @@
             if (mode != null) {
                 mActionMode = mode;
             } else {
-                if (mActionModeView == null) {
-                    if (isFloating()) {
-                        // Use the action bar theme.
-                        final TypedValue outValue = new TypedValue();
-                        final Theme baseTheme = mContext.getTheme();
-                        baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
-
-                        final Context actionBarContext;
-                        if (outValue.resourceId != 0) {
-                            final Theme actionBarTheme = mContext.getResources().newTheme();
-                            actionBarTheme.setTo(baseTheme);
-                            actionBarTheme.applyStyle(outValue.resourceId, true);
-
-                            actionBarContext = new ContextThemeWrapper(mContext, 0);
-                            actionBarContext.getTheme().setTo(actionBarTheme);
-                        } else {
-                            actionBarContext = mContext;
-                        }
-
-                        mActionModeView = new ActionBarContextView(actionBarContext);
-                        mActionModePopup = new PopupWindow(actionBarContext, null,
-                                R.attr.actionModePopupWindowStyle);
-                        mActionModePopup.setWindowLayoutType(
-                                WindowManager.LayoutParams.TYPE_APPLICATION);
-                        mActionModePopup.setContentView(mActionModeView);
-                        mActionModePopup.setWidth(MATCH_PARENT);
-
-                        actionBarContext.getTheme().resolveAttribute(
-                                R.attr.actionBarSize, outValue, true);
-                        final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
-                                actionBarContext.getResources().getDisplayMetrics());
-                        mActionModeView.setContentHeight(height);
-                        mActionModePopup.setHeight(WRAP_CONTENT);
-                        mShowActionModePopup = new Runnable() {
-                            public void run() {
-                                mActionModePopup.showAtLocation(
-                                        mActionModeView.getApplicationWindowToken(),
-                                        Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
-                            }
-                        };
-                    } else {
-                        ViewStub stub = (ViewStub) findViewById(
-                                R.id.action_mode_bar_stub);
-                        if (stub != null) {
-                            mActionModeView = (ActionBarContextView) stub.inflate();
-                        }
-                    }
-                }
-
                 if (mActionModeView != null) {
                     mActionModeView.killMode();
-                    mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView,
-                            wrappedCallback, mActionModePopup == null);
-                    if (callback.onCreateActionMode(mode, mode.getMenu())) {
-                        mode.invalidate();
-                        mActionModeView.initForMode(mode);
-                        mActionModeView.setVisibility(View.VISIBLE);
-                        mActionMode = mode;
-                        if (mActionModePopup != null) {
-                            post(mShowActionModePopup);
-                        }
-                        mActionModeView.sendAccessibilityEvent(
-                                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-                    } else {
-                        mActionMode = null;
-                    }
+                }
+                ActionModeWrapper wrapperMode = new ActionModeWrapper(
+                        mContext, wrappedCallback, new StandaloneActionModeProvider());
+                if (callback.onCreateActionMode(wrapperMode, wrapperMode.getMenu())) {
+                    mActionMode = wrapperMode;
+                    wrapperMode.lockType();
+                    mActionMode.invalidate();
+                } else {
+                    mActionMode = null;
                 }
             }
             if (mActionMode != null && getCallback() != null && !isDestroyed()) {
@@ -3251,6 +3198,82 @@
         }
 
         /**
+         * Encapsulates the view creation for {@link StandaloneActionMode}.
+         */
+        private class StandaloneActionModeProvider
+                implements ActionModeWrapper.ActionModeProvider {
+
+            @Override
+            public ActionMode createActionMode(android.view.ActionMode.Callback callback,
+                    MenuBuilder menuBuilder) {
+                if (mActionModeView == null) {
+                    if (isFloating()) {
+                        // Use the action bar theme.
+                        final TypedValue outValue = new TypedValue();
+                        final Theme baseTheme = mContext.getTheme();
+                        baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
+
+                        final Context actionBarContext;
+                        if (outValue.resourceId != 0) {
+                            final Theme actionBarTheme = mContext.getResources().newTheme();
+                            actionBarTheme.setTo(baseTheme);
+                            actionBarTheme.applyStyle(outValue.resourceId, true);
+
+                            actionBarContext = new ContextThemeWrapper(mContext, 0);
+                            actionBarContext.getTheme().setTo(actionBarTheme);
+                        } else {
+                            actionBarContext = mContext;
+                        }
+
+                        mActionModeView = new ActionBarContextView(actionBarContext);
+                        mActionModePopup = new PopupWindow(actionBarContext, null,
+                                R.attr.actionModePopupWindowStyle);
+                        mActionModePopup.setWindowLayoutType(
+                                WindowManager.LayoutParams.TYPE_APPLICATION);
+                        mActionModePopup.setContentView(mActionModeView);
+                        mActionModePopup.setWidth(MATCH_PARENT);
+
+                        actionBarContext.getTheme().resolveAttribute(
+                                R.attr.actionBarSize, outValue, true);
+                        final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
+                                actionBarContext.getResources().getDisplayMetrics());
+                        mActionModeView.setContentHeight(height);
+                        mActionModePopup.setHeight(WRAP_CONTENT);
+                        mShowActionModePopup = new Runnable() {
+                            public void run() {
+                                mActionModePopup.showAtLocation(
+                                        mActionModeView.getApplicationWindowToken(),
+                                        Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
+                            }
+                        };
+                    } else {
+                        ViewStub stub = (ViewStub) findViewById(
+                                R.id.action_mode_bar_stub);
+                        if (stub != null) {
+                            mActionModeView = (ActionBarContextView) stub.inflate();
+                        }
+                    }
+                }
+                if (mActionModeView != null) {
+                    ActionMode mode = new StandaloneActionMode(
+                            mActionModeView.getContext(), mActionModeView,
+                            callback, mActionModePopup == null, menuBuilder);
+                    mActionModeView.killMode();
+                    mActionModeView.initForMode(mode);
+                    mActionModeView.setVisibility(View.VISIBLE);
+                    if (mActionModePopup != null) {
+                        post(mShowActionModePopup);
+                    }
+                    mActionModeView.sendAccessibilityEvent(
+                            AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    return mode;
+                }
+                return null;
+            }
+
+        }
+
+        /**
          * Clears out internal reference when the action mode is destroyed.
          */
         private class ActionModeCallbackWrapper implements ActionMode.Callback {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ad4a048..df0838f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,8 +16,7 @@
 
 package android.view;
 
-import com.android.internal.R;
-
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -27,16 +26,18 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Log;
 import android.util.LongSparseArray;
-import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
+import com.android.internal.R;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -74,6 +75,14 @@
         PROFILE_PROPERTY_VISUALIZE_BARS,
     };
 
+    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
+    private static final int FLAG_DUMP_RESET        = 1 << 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DumpFlags {}
+
     // Size of the rendered content.
     private int mWidth, mHeight;
 
@@ -93,12 +102,12 @@
     private final float mLightRadius;
     private final int mAmbientShadowAlpha;
     private final int mSpotShadowAlpha;
+    private final float mDensity;
 
     private long mNativeProxy;
     private boolean mInitialized = false;
     private RenderNode mRootNode;
     private Choreographer mChoreographer;
-    private boolean mProfilingEnabled;
     private boolean mRootNodeNeedsUpdate;
 
     ThreadedRenderer(Context context, boolean translucent) {
@@ -110,6 +119,7 @@
                 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
         mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
         a.recycle();
+        mDensity = context.getResources().getDisplayMetrics().density;
 
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
@@ -214,7 +224,7 @@
         mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
         nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
                 lightX, mLightY, mLightZ, mLightRadius,
-                mAmbientShadowAlpha, mSpotShadowAlpha);
+                mAmbientShadowAlpha, mSpotShadowAlpha, mDensity);
     }
 
     @Override
@@ -233,32 +243,25 @@
     }
 
     @Override
-    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
+    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
         pw.flush();
-        nDumpProfileInfo(mNativeProxy, fd);
-    }
-
-    private static int search(String[] values, String value) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i].equals(value)) return i;
+        int flags = 0;
+        for (int i = 0; i < args.length; i++) {
+            switch (args[i]) {
+                case "framestats":
+                    flags |= FLAG_DUMP_FRAMESTATS;
+                    break;
+                case "reset":
+                    flags |= FLAG_DUMP_RESET;
+                    break;
+            }
         }
-        return -1;
-    }
-
-    private static boolean checkIfProfilingRequested() {
-        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
-        int graphType = search(VISUALIZERS, profiling);
-        return (graphType >= 0) || Boolean.parseBoolean(profiling);
+        nDumpProfileInfo(mNativeProxy, fd, flags);
     }
 
     @Override
     boolean loadSystemProperties() {
         boolean changed = nLoadSystemProperties(mNativeProxy);
-        boolean wantProfiling = checkIfProfilingRequested();
-        if (wantProfiling != mProfilingEnabled) {
-            mProfilingEnabled = wantProfiling;
-            changed = true;
-        }
         if (changed) {
             invalidateRoot();
         }
@@ -307,20 +310,12 @@
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
         attachInfo.mIgnoreDirtyState = true;
-        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
-        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
 
-        long recordDuration = 0;
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime();
-        }
+        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
+        choreographer.mFrameInfo.markDrawStart();
 
         updateRootDisplayList(view, callbacks);
 
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime() - recordDuration;
-        }
-
         attachInfo.mIgnoreDirtyState = false;
 
         // register animating rendernodes which started animating prior to renderer
@@ -337,8 +332,8 @@
             attachInfo.mPendingAnimatingRenderNodes = null;
         }
 
-        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
-                recordDuration, view.getResources().getDisplayMetrics().density);
+        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
             setEnabled(false);
             attachInfo.mViewRootImpl.mSurface.release();
@@ -500,10 +495,9 @@
     private static native boolean nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height,
             float lightX, float lightY, float lightZ, float lightRadius,
-            int ambientShadowAlpha, int spotShadowAlpha);
+            int ambientShadowAlpha, int spotShadowAlpha, float density);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native int nSyncAndDrawFrame(long nativeProxy,
-            long frameTimeNanos, long recordDuration, float density);
+    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
     private static native void nDestroy(long nativeProxy);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
@@ -523,5 +517,6 @@
     private static native void nStopDrawing(long nativeProxy);
     private static native void nNotifyFramePending(long nativeProxy);
 
-    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
+    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
+            @DumpFlags int dumpFlags);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index f99d2d5..502d5ee 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -16,7 +16,9 @@
 
 package android.view;
 
+import android.animation.Animator;
 import android.animation.AnimatorInflater;
+import android.animation.ObjectAnimator;
 import android.animation.StateListAnimator;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
@@ -32,13 +34,10 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Insets;
-import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
 import android.graphics.Matrix;
 import android.graphics.Outline;
 import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.PathMeasure;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PorterDuff;
@@ -4326,9 +4325,7 @@
      * @hide This is the real method; the public one is shimmed to be safe to call from apps.
      */
     protected void initializeFadingEdgeInternal(TypedArray a) {
-        initScrollCache();
-
-        mScrollCache.fadingEdgeLength = a.getDimensionPixelSize(
+        getScrollCache().fadingEdgeLength = a.getDimensionPixelSize(
                 R.styleable.View_fadingEdgeLength,
                 ViewConfiguration.get(mContext).getScaledFadingEdgeLength());
     }
@@ -4362,8 +4359,7 @@
      *        content in this view is visible.
      */
     public void setFadingEdgeLength(int length) {
-        initScrollCache();
-        mScrollCache.fadingEdgeLength = length;
+        getScrollCache().fadingEdgeLength = length;
     }
 
     /**
@@ -4467,10 +4463,7 @@
      * @hide
      */
     protected void initializeScrollbarsInternal(TypedArray a) {
-        initScrollCache();
-
-        final ScrollabilityCache scrollabilityCache = mScrollCache;
-
+        final ScrollabilityCache scrollabilityCache = getScrollCache();
         if (scrollabilityCache.scrollBar == null) {
             scrollabilityCache.scrollBar = new ScrollBarDrawable();
             scrollabilityCache.scrollBar.setCallback(this);
@@ -4478,23 +4471,16 @@
         }
 
         final boolean fadeScrollbars = a.getBoolean(R.styleable.View_fadeScrollbars, true);
-
-        if (!fadeScrollbars) {
-            scrollabilityCache.state = ScrollabilityCache.ON;
-        }
-        scrollabilityCache.fadeScrollBars = fadeScrollbars;
-
+        scrollabilityCache.setFadingEnabled(fadeScrollbars);
 
         scrollabilityCache.scrollBarFadeDuration = a.getInt(
-                R.styleable.View_scrollbarFadeDuration, ViewConfiguration
-                        .getScrollBarFadeDuration());
+                R.styleable.View_scrollbarFadeDuration,
+                ViewConfiguration.getScrollBarFadeDuration());
         scrollabilityCache.scrollBarDefaultDelayBeforeFade = a.getInt(
                 R.styleable.View_scrollbarDefaultDelayBeforeFade,
                 ViewConfiguration.getScrollDefaultDelay());
-
-
         scrollabilityCache.scrollBarSize = a.getDimensionPixelSize(
-                com.android.internal.R.styleable.View_scrollbarSize,
+                R.styleable.View_scrollbarSize,
                 ViewConfiguration.get(mContext).getScaledScrollBarSize());
 
         Drawable track = a.getDrawable(R.styleable.View_scrollbarTrackHorizontal);
@@ -4539,18 +4525,12 @@
     }
 
     /**
-     * <p>
-     * Initalizes the scrollability cache if necessary.
-     * </p>
+     * Returns the scrollability cache, initializing a new cache if necessary.
      */
-    private void initScrollCache() {
-        if (mScrollCache == null) {
-            mScrollCache = new ScrollabilityCache(ViewConfiguration.get(mContext), this);
-        }
-    }
-
     private ScrollabilityCache getScrollCache() {
-        initScrollCache();
+        if (mScrollCache == null) {
+            mScrollCache = new ScrollabilityCache(this);
+        }
         return mScrollCache;
     }
 
@@ -11571,31 +11551,30 @@
      * @see #setVerticalScrollBarEnabled(boolean)
      */
     protected boolean awakenScrollBars() {
-        return mScrollCache != null &&
-                awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
+        return mScrollCache != null
+                && awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade, true);
     }
 
     /**
      * Trigger the scrollbars to draw.
+     * <p>
      * This method differs from awakenScrollBars() only in its default duration.
      * initialAwakenScrollBars() will show the scroll bars for longer than
      * usual to give the user more of a chance to notice them.
      *
      * @return true if the animation is played, false otherwise.
+     * @see #awakenScrollBars()
      */
     private boolean initialAwakenScrollBars() {
-        return mScrollCache != null &&
-                awakenScrollBars(mScrollCache.scrollBarDefaultDelayBeforeFade * 4, true);
+        return mScrollCache != null
+                && awakenScrollBars(mScrollCache.scrollBarDelayBeforeInitialFade, true);
     }
 
     /**
-     * <p>
      * Trigger the scrollbars to draw. When invoked this method starts an
      * animation to fade the scrollbars out after a fixed delay. If a subclass
      * provides animated scrolling, the start delay should equal the duration of
      * the scrolling animation.
-     * </p>
-     *
      * <p>
      * The animation starts only if at least one of the scrollbars is enabled,
      * as specified by {@link #isHorizontalScrollBarEnabled()} and
@@ -11603,18 +11582,14 @@
      * this method returns true, and false otherwise. If the animation is
      * started, this method calls {@link #invalidate()}; in that case the caller
      * should not call {@link #invalidate()}.
-     * </p>
-     *
      * <p>
      * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
-     * </p>
      *
-     * @param startDelay the delay, in milliseconds, after which the animation
-     *        should start; when the delay is 0, the animation starts
-     *        immediately
+     * @param fadeOutDelay the delay in milliseconds before the fade out
+     *                     animation should start, or 0 to start the animation
+     *                     immediately
      * @return true if the animation is played, false otherwise
-     *
      * @see #scrollBy(int, int)
      * @see #scrollTo(int, int)
      * @see #isHorizontalScrollBarEnabled()
@@ -11622,18 +11597,15 @@
      * @see #setHorizontalScrollBarEnabled(boolean)
      * @see #setVerticalScrollBarEnabled(boolean)
      */
-    protected boolean awakenScrollBars(int startDelay) {
-        return awakenScrollBars(startDelay, true);
+    protected boolean awakenScrollBars(int fadeOutDelay) {
+        return awakenScrollBars(fadeOutDelay, true);
     }
 
     /**
-     * <p>
      * Trigger the scrollbars to draw. When invoked this method starts an
      * animation to fade the scrollbars out after a fixed delay. If a subclass
      * provides animated scrolling, the start delay should equal the duration of
      * the scrolling animation.
-     * </p>
-     *
      * <p>
      * The animation starts only if at least one of the scrollbars is enabled,
      * as specified by {@link #isHorizontalScrollBarEnabled()} and
@@ -11642,21 +11614,18 @@
      * started, this method calls {@link #invalidate()} if the invalidate parameter
      * is set to true; in that case the caller
      * should not call {@link #invalidate()}.
-     * </p>
-     *
      * <p>
      * This method should be invoked every time a subclass directly updates the
      * scroll parameters.
-     * </p>
+     * <p>
+     * <strong>Note:</strong> If the view has not explicitly requested
+     * scrollbars prior calling this method, this is a no-op.
      *
-     * @param startDelay the delay, in milliseconds, after which the animation
-     *        should start; when the delay is 0, the animation starts
-     *        immediately
-     *
-     * @param invalidate Whether this method should call invalidate
-     *
+     * @param fadeOutDelay the delay in milliseconds before the fade out
+     *                     animation should start, or 0 to start the animation
+     *                     immediately
+     * @param invalidate whether this method should call invalidate
      * @return true if the animation is played, false otherwise
-     *
      * @see #scrollBy(int, int)
      * @see #scrollTo(int, int)
      * @see #isHorizontalScrollBarEnabled()
@@ -11664,50 +11633,15 @@
      * @see #setHorizontalScrollBarEnabled(boolean)
      * @see #setVerticalScrollBarEnabled(boolean)
      */
-    protected boolean awakenScrollBars(int startDelay, boolean invalidate) {
-        final ScrollabilityCache scrollCache = mScrollCache;
-
-        if (scrollCache == null || !scrollCache.fadeScrollBars) {
+    protected boolean awakenScrollBars(int fadeOutDelay, boolean invalidate) {
+        if (mScrollCache == null
+                || (!isHorizontalScrollBarEnabled() && !isVerticalScrollBarEnabled())) {
+            // We're not supposed to show scroll bars right now.
             return false;
         }
 
-        if (scrollCache.scrollBar == null) {
-            scrollCache.scrollBar = new ScrollBarDrawable();
-            scrollCache.scrollBar.setCallback(this);
-            scrollCache.scrollBar.setState(getDrawableState());
-        }
-
-        if (isHorizontalScrollBarEnabled() || isVerticalScrollBarEnabled()) {
-
-            if (invalidate) {
-                // Invalidate to show the scrollbars
-                postInvalidateOnAnimation();
-            }
-
-            if (scrollCache.state == ScrollabilityCache.OFF) {
-                // FIXME: this is copied from WindowManagerService.
-                // We should get this value from the system when it
-                // is possible to do so.
-                final int KEY_REPEAT_FIRST_DELAY = 750;
-                startDelay = Math.max(KEY_REPEAT_FIRST_DELAY, startDelay);
-            }
-
-            // Tell mScrollCache when we should start fading. This may
-            // extend the fade start time if one was already scheduled
-            long fadeStartTime = AnimationUtils.currentAnimationTimeMillis() + startDelay;
-            scrollCache.fadeStartTime = fadeStartTime;
-            scrollCache.state = ScrollabilityCache.ON;
-
-            // Schedule our fader to run, unscheduling any old ones first
-            if (mAttachInfo != null) {
-                mAttachInfo.mHandler.removeCallbacks(scrollCache);
-                mAttachInfo.mHandler.postAtTime(scrollCache, fadeStartTime);
-            }
-
-            return true;
-        }
-
-        return false;
+        mScrollCache.awakenScrollBars(fadeOutDelay);
+        return true;
     }
 
     /**
@@ -12388,7 +12322,7 @@
     public void setHorizontalFadingEdgeEnabled(boolean horizontalFadingEdgeEnabled) {
         if (isHorizontalFadingEdgeEnabled() != horizontalFadingEdgeEnabled) {
             if (horizontalFadingEdgeEnabled) {
-                initScrollCache();
+                getScrollCache();
             }
 
             mViewFlags ^= FADING_EDGE_HORIZONTAL;
@@ -12425,7 +12359,7 @@
     public void setVerticalFadingEdgeEnabled(boolean verticalFadingEdgeEnabled) {
         if (isVerticalFadingEdgeEnabled() != verticalFadingEdgeEnabled) {
             if (verticalFadingEdgeEnabled) {
-                initScrollCache();
+                getScrollCache();
             }
 
             mViewFlags ^= FADING_EDGE_VERTICAL;
@@ -12565,14 +12499,7 @@
      * @attr ref android.R.styleable#View_fadeScrollbars
      */
     public void setScrollbarFadingEnabled(boolean fadeScrollbars) {
-        initScrollCache();
-        final ScrollabilityCache scrollabilityCache = mScrollCache;
-        scrollabilityCache.fadeScrollBars = fadeScrollbars;
-        if (fadeScrollbars) {
-            scrollabilityCache.state = ScrollabilityCache.OFF;
-        } else {
-            scrollabilityCache.state = ScrollabilityCache.ON;
-        }
+        getScrollCache().setFadingEnabled(fadeScrollbars);
     }
 
     /**
@@ -12584,7 +12511,7 @@
      * @attr ref android.R.styleable#View_fadeScrollbars
      */
     public boolean isScrollbarFadingEnabled() {
-        return mScrollCache != null && mScrollCache.fadeScrollBars;
+        return mScrollCache != null && mScrollCache.isFadingEnabled();
     }
 
     /**
@@ -12866,129 +12793,85 @@
     }
 
     /**
-     * <p>Request the drawing of the horizontal and the vertical scrollbar. The
-     * scrollbars are painted only if they have been awakened first.</p>
+     * Request the drawing of the horizontal and the vertical scrollbar. The
+     * scrollbars are painted only if they have been awakened first.
      *
      * @param canvas the canvas on which to draw the scrollbars
-     *
      * @see #awakenScrollBars(int)
      */
     protected final void onDrawScrollBars(Canvas canvas) {
-        // scrollbars are drawn only when the animation is running
         final ScrollabilityCache cache = mScrollCache;
-        if (cache != null) {
+        if (cache == null) {
+            // This view does not currently support scrolling.
+            return;
+        }
 
-            int state = cache.state;
+        final int viewFlags = mViewFlags;
+        final boolean drawHorizontalScrollBar =
+            (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
+        final boolean drawVerticalScrollBar =
+            (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
+            && !isVerticalScrollBarHidden();
+        if (!drawVerticalScrollBar && !drawHorizontalScrollBar) {
+            // This view does not currently draw scrollbars.
+            return;
+        }
 
-            if (state == ScrollabilityCache.OFF) {
-                return;
+        final ScrollBarDrawable scrollBar = cache.scrollBar;
+        final int width = mRight - mLeft;
+        final int height = mBottom - mTop;
+        final int scrollX = mScrollX;
+        final int scrollY = mScrollY;
+        final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
+
+        if (drawHorizontalScrollBar) {
+            int size = scrollBar.getSize(false);
+            if (size <= 0) {
+                size = cache.scrollBarSize;
             }
 
-            boolean invalidate = false;
+            scrollBar.setParameters(computeHorizontalScrollRange(), computeHorizontalScrollOffset(),
+                    computeHorizontalScrollExtent(), false);
+            final int verticalScrollBarGap = drawVerticalScrollBar ?
+                    getVerticalScrollbarWidth() : 0;
 
-            if (state == ScrollabilityCache.FADING) {
-                // We're fading -- get our fade interpolation
-                if (cache.interpolatorValues == null) {
-                    cache.interpolatorValues = new float[1];
-                }
+            final int left = scrollX + (mPaddingLeft & inside);
+            final int right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
+            final int top = scrollY + height - size - (mUserPaddingBottom & inside);
+            final int bottom = top + size;
 
-                float[] values = cache.interpolatorValues;
+            onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
+        }
 
-                // Stops the animation if we're done
-                if (cache.scrollBarInterpolator.timeToValues(values) ==
-                        Interpolator.Result.FREEZE_END) {
-                    cache.state = ScrollabilityCache.OFF;
-                } else {
-                    cache.scrollBar.mutate().setAlpha(Math.round(values[0]));
-                }
+        if (drawVerticalScrollBar) {
+            int size = scrollBar.getSize(true);
+            if (size <= 0) {
+                size = cache.scrollBarSize;
+            }
 
-                // This will make the scroll bars inval themselves after
-                // drawing. We only want this when we're fading so that
-                // we prevent excessive redraws
-                invalidate = true;
+            scrollBar.setParameters(computeVerticalScrollRange(), computeVerticalScrollOffset(),
+                    computeVerticalScrollExtent(), true);
+
+            final int verticalScrollbarPosition;
+            if (mVerticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
+                verticalScrollbarPosition = isLayoutRtl() ?
+                        SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
             } else {
-                // We're just on -- but we may have been fading before so
-                // reset alpha
-                cache.scrollBar.mutate().setAlpha(255);
+                verticalScrollbarPosition = mVerticalScrollbarPosition;
             }
 
-
-            final int viewFlags = mViewFlags;
-
-            final boolean drawHorizontalScrollBar =
-                (viewFlags & SCROLLBARS_HORIZONTAL) == SCROLLBARS_HORIZONTAL;
-            final boolean drawVerticalScrollBar =
-                (viewFlags & SCROLLBARS_VERTICAL) == SCROLLBARS_VERTICAL
-                && !isVerticalScrollBarHidden();
-
-            if (drawVerticalScrollBar || drawHorizontalScrollBar) {
-                final int width = mRight - mLeft;
-                final int height = mBottom - mTop;
-
-                final ScrollBarDrawable scrollBar = cache.scrollBar;
-
-                final int scrollX = mScrollX;
-                final int scrollY = mScrollY;
-                final int inside = (viewFlags & SCROLLBARS_OUTSIDE_MASK) == 0 ? ~0 : 0;
-
-                int left;
-                int top;
-                int right;
-                int bottom;
-
-                if (drawHorizontalScrollBar) {
-                    int size = scrollBar.getSize(false);
-                    if (size <= 0) {
-                        size = cache.scrollBarSize;
-                    }
-
-                    scrollBar.setParameters(computeHorizontalScrollRange(),
-                                            computeHorizontalScrollOffset(),
-                                            computeHorizontalScrollExtent(), false);
-                    final int verticalScrollBarGap = drawVerticalScrollBar ?
-                            getVerticalScrollbarWidth() : 0;
-                    top = scrollY + height - size - (mUserPaddingBottom & inside);
-                    left = scrollX + (mPaddingLeft & inside);
-                    right = scrollX + width - (mUserPaddingRight & inside) - verticalScrollBarGap;
-                    bottom = top + size;
-                    onDrawHorizontalScrollBar(canvas, scrollBar, left, top, right, bottom);
-                    if (invalidate) {
-                        invalidate(left, top, right, bottom);
-                    }
-                }
-
-                if (drawVerticalScrollBar) {
-                    int size = scrollBar.getSize(true);
-                    if (size <= 0) {
-                        size = cache.scrollBarSize;
-                    }
-
-                    scrollBar.setParameters(computeVerticalScrollRange(),
-                                            computeVerticalScrollOffset(),
-                                            computeVerticalScrollExtent(), true);
-                    int verticalScrollbarPosition = mVerticalScrollbarPosition;
-                    if (verticalScrollbarPosition == SCROLLBAR_POSITION_DEFAULT) {
-                        verticalScrollbarPosition = isLayoutRtl() ?
-                                SCROLLBAR_POSITION_LEFT : SCROLLBAR_POSITION_RIGHT;
-                    }
-                    switch (verticalScrollbarPosition) {
-                        default:
-                        case SCROLLBAR_POSITION_RIGHT:
-                            left = scrollX + width - size - (mUserPaddingRight & inside);
-                            break;
-                        case SCROLLBAR_POSITION_LEFT:
-                            left = scrollX + (mUserPaddingLeft & inside);
-                            break;
-                    }
-                    top = scrollY + (mPaddingTop & inside);
-                    right = left + size;
-                    bottom = scrollY + height - (mUserPaddingBottom & inside);
-                    onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
-                    if (invalidate) {
-                        invalidate(left, top, right, bottom);
-                    }
-                }
+            final int left;
+            if (verticalScrollbarPosition == SCROLLBAR_POSITION_LEFT) {
+                left = scrollX + (mUserPaddingLeft & inside);
+            } else {
+                left = scrollX + width - size - (mUserPaddingRight & inside);
             }
+
+            final int top = scrollY + (mPaddingTop & inside);
+            final int right = left + size;
+            final int bottom = scrollY + height - (mUserPaddingBottom & inside);
+
+            onDrawVerticalScrollBar(canvas, scrollBar, left, top, right, bottom);
         }
     }
 
@@ -15352,7 +15235,7 @@
                 canvas.saveLayer(right - length, top, right, bottom, null, flags);
             }
         } else {
-            scrollabilityCache.setFadeColor(solidColor);
+            scrollabilityCache.setFadingEdgeColor(solidColor);
         }
 
         // Step 3, draw the content
@@ -15362,9 +15245,9 @@
         dispatchDraw(canvas);
 
         // Step 5, draw the fade effect and restore layers
-        final Paint p = scrollabilityCache.paint;
+        final Paint p = scrollabilityCache.fadingEdgePaint;
         final Matrix matrix = scrollabilityCache.matrix;
-        final Shader fade = scrollabilityCache.shader;
+        final Shader fade = scrollabilityCache.fadingEdgeShader;
 
         if (drawTop) {
             matrix.setScale(1, fadeHeight * topFadeStrength);
@@ -20624,121 +20507,164 @@
     }
 
     /**
-     * <p>ScrollabilityCache holds various fields used by a View when scrolling
+     * ScrollabilityCache holds various fields used by a View when scrolling
      * is supported. This avoids keeping too many unused fields in most
-     * instances of View.</p>
+     * instances of View.
      */
-    private static class ScrollabilityCache implements Runnable {
+    private static class ScrollabilityCache {
+        public final Paint fadingEdgePaint = new Paint();
+        public final Matrix matrix = new Matrix();
+
+        /** The view that owns this cache. */
+        private final View mHost;
 
         /**
-         * Scrollbars are not visible
+         * Minimum delay in milliseconds before the fade-out animation begins.
+         * Only used if the scrollbar was previously invisible.
          */
-        public static final int OFF = 0;
+        private static final int MIN_FADE_DELAY_FROM_OFF = 750;
 
         /**
-         * Scrollbars are visible
+         * Default delay in milliseconds before the fade-out animation begins.
          */
-        public static final int ON = 1;
-
-        /**
-         * Scrollbars are fading away
-         */
-        public static final int FADING = 2;
-
-        public boolean fadeScrollBars;
-
-        public int fadingEdgeLength;
         public int scrollBarDefaultDelayBeforeFade;
+
+        /**
+         * Delay in milliseconds before the fade-out animation begins. Only
+         * used if the scrollbar is being shown to the user for the first time.
+         */
+        public int scrollBarDelayBeforeInitialFade;
+
+        /** Duration in milliseconds of the fade-out animation. */
         public int scrollBarFadeDuration;
 
-        public int scrollBarSize;
         public ScrollBarDrawable scrollBar;
-        public float[] interpolatorValues;
-        public View host;
-
-        public final Paint paint;
-        public final Matrix matrix;
-        public Shader shader;
-
-        public final Interpolator scrollBarInterpolator = new Interpolator(1, 2);
-
-        private static final float[] OPAQUE = { 255 };
-        private static final float[] TRANSPARENT = { 0.0f };
+        public Shader fadingEdgeShader;
+        public int fadingEdgeLength;
+        public int scrollBarSize;
 
         /**
-         * When fading should start. This time moves into the future every time
-         * a new scroll happens. Measured based on SystemClock.uptimeMillis()
+         * Whether scrollbar fading is enabled. If false, scrollbars are always
+         * visible.
          */
-        public long fadeStartTime;
+        private boolean mIsFadingEnabled;
 
+        private Animator mFadeAnim;
+        private int mFadingEdgeLastColor;
 
-        /**
-         * The current state of the scrollbars: ON, OFF, or FADING
-         */
-        public int state = OFF;
+        public ScrollabilityCache(View host) {
+            mHost = host;
 
-        private int mLastColor;
-
-        public ScrollabilityCache(ViewConfiguration configuration, View host) {
-            fadingEdgeLength = configuration.getScaledFadingEdgeLength();
-            scrollBarSize = configuration.getScaledScrollBarSize();
-            scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
             scrollBarFadeDuration = ViewConfiguration.getScrollBarFadeDuration();
+            scrollBarDefaultDelayBeforeFade = ViewConfiguration.getScrollDefaultDelay();
+            scrollBarDelayBeforeInitialFade = ViewConfiguration.getScrollDefaultInitialDelay();
 
-            paint = new Paint();
-            matrix = new Matrix();
-            // use use a height of 1, and then wack the matrix each time we
-            // actually use it.
-            shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
-            paint.setShader(shader);
-            paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+            final ViewConfiguration configuration = ViewConfiguration.get(host.getContext());
+            scrollBarSize = configuration.getScaledScrollBarSize();
+            fadingEdgeLength = configuration.getScaledFadingEdgeLength();
 
-            this.host = host;
+            // Force the fading edge color to change.
+            mFadingEdgeLastColor = -1;
+            setFadingEdgeColor(0);
         }
 
-        public void setFadeColor(int color) {
-            if (color != mLastColor) {
-                mLastColor = color;
+        public void setFadingEdgeColor(int color) {
+            if (mFadingEdgeLastColor != color) {
+                mFadingEdgeLastColor = color;
 
+                final int color0;
+                final int color1;
+                final PorterDuffXfermode xfermode;
                 if (color != 0) {
-                    shader = new LinearGradient(0, 0, 0, 1, color | 0xFF000000,
-                            color & 0x00FFFFFF, Shader.TileMode.CLAMP);
-                    paint.setShader(shader);
-                    // Restore the default transfer mode (src_over)
-                    paint.setXfermode(null);
+                    color0 = color | 0xFF000000;
+                    color1 = color & 0x00FFFFFF;
+                    xfermode = null;
                 } else {
-                    shader = new LinearGradient(0, 0, 0, 1, 0xFF000000, 0, Shader.TileMode.CLAMP);
-                    paint.setShader(shader);
-                    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
+                    color0 = 0xFF000000;
+                    color1 = 0;
+                    xfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
                 }
+
+                // Use a height of 1 and then whack the matrix each time we
+                // actually use it.
+                fadingEdgeShader = new LinearGradient(
+                        0, 0, 0, 1, color0, color1, Shader.TileMode.CLAMP);
+                fadingEdgePaint.setShader(fadingEdgeShader);
+                fadingEdgePaint.setXfermode(xfermode);
             }
         }
 
-        public void run() {
-            long now = AnimationUtils.currentAnimationTimeMillis();
-            if (now >= fadeStartTime) {
+        public void setFadingEnabled(boolean enabled) {
+            if (mIsFadingEnabled != enabled) {
+                mIsFadingEnabled = enabled;
 
-                // the animation fades the scrollbars out by changing
-                // the opacity (alpha) from fully opaque to fully
-                // transparent
-                int nextFrame = (int) now;
-                int framesCount = 0;
-
-                Interpolator interpolator = scrollBarInterpolator;
-
-                // Start opaque
-                interpolator.setKeyFrame(framesCount++, nextFrame, OPAQUE);
-
-                // End transparent
-                nextFrame += scrollBarFadeDuration;
-                interpolator.setKeyFrame(framesCount, nextFrame, TRANSPARENT);
-
-                state = FADING;
-
-                // Kick off the fade animation
-                host.invalidate(true);
+                setFadingAlpha(enabled ? 0 : 255);
             }
         }
+
+        public boolean isFadingEnabled() {
+            return mIsFadingEnabled;
+        }
+
+        /**
+         * Cancels any ongoing or pending fade animations and immediately sets
+         * the scroll bar alpha value.
+         *
+         * @param alpha the scrollbar alpha value
+         */
+        public void setFadingAlpha(int alpha) {
+            if (mFadeAnim != null) {
+                mFadeAnim.cancel();
+                mFadeAnim = null;
+            }
+            mHost.removeCallbacks(mFadeOutRunnable);
+
+            scrollBar.setAlpha(alpha);
+        }
+
+        /**
+         * If fading is enabled, cancels any ongoing or pending fade animations
+         * and immediately sets the scroll bar alpha value to the maximum, then
+         * posts a delayed fade-out animation.
+         *
+         * @param fadeOutDelay the delay before the fade-out animation starts
+         * @return {@code true} if the scroll bars changed, false otherwise
+         */
+        public boolean awakenScrollBars(int fadeOutDelay) {
+            if (!mIsFadingEnabled) {
+                return false;
+            }
+
+            if (scrollBar == null) {
+                scrollBar = new ScrollBarDrawable();
+                scrollBar.setCallback(mHost);
+                scrollBar.setState(mHost.getDrawableState());
+            }
+
+            // Removes pending callbacks.
+            setFadingAlpha(255);
+
+            final int startingAlpha = scrollBar.getAlpha();
+            if (startingAlpha == 0) {
+                fadeOutDelay = Math.max(ScrollabilityCache.MIN_FADE_DELAY_FROM_OFF, fadeOutDelay);
+            }
+
+            mHost.postDelayed(mFadeOutRunnable, fadeOutDelay);
+
+            return true;
+        }
+
+        private final Runnable mFadeOutRunnable = new Runnable() {
+            @Override
+            public void run() {
+                final ObjectAnimator anim = ObjectAnimator.ofInt(
+                        scrollBar, ScrollBarDrawable.ALPHA, 0);
+                anim.setDuration(scrollBarFadeDuration);
+                anim.start();
+
+                mFadeAnim = anim;
+            }
+        };
     }
 
     /**
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4e91ad4..d733513 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -47,6 +47,12 @@
     private static final int SCROLL_BAR_DEFAULT_DELAY = 300;
 
     /**
+     * Default delay before the scrollbars fade in milliseconds for the first
+     * time they are shown to the user.
+     */
+    private static final int SCROLL_BAR_DEFAULT_INITIAL_DELAY = 1500;
+
+    /**
      * Defines the length of the fading edges in dips
      */
     private static final int FADING_EDGE_LENGTH = 12;
@@ -395,13 +401,23 @@
     }
 
     /**
-     * @return Default delay before the scrollbars fade in milliseconds
+     * @return Default delay in milliseconds before the scrollbars fade out
+     *         after they have been awoken.
      */
     public static int getScrollDefaultDelay() {
         return SCROLL_BAR_DEFAULT_DELAY;
     }
 
     /**
+     * @return Default delay in milliseconds before the scrollbars fade out
+     *         after they are initially shown to the user.
+     * @hide Pending cleanup of ViewConfiguration values.
+     */
+    public static int getScrollDefaultInitialDelay() {
+        return SCROLL_BAR_DEFAULT_INITIAL_DELAY;
+    }
+
+    /**
      * @return the length of the fading edges in dips
      *
      * @deprecated Use {@link #getScaledFadingEdgeLength()} instead.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 24fae8a..a5fa5ed 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -47,6 +47,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManager;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -56,6 +57,7 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
@@ -837,6 +839,7 @@
                 final int newDisplayState = mDisplay.getState();
                 if (oldDisplayState != newDisplayState) {
                     mAttachInfo.mDisplayState = newDisplayState;
+                    pokeDrawLockIfNeeded();
                     if (oldDisplayState != Display.STATE_UNKNOWN) {
                         final int oldScreenState = toViewScreenState(oldDisplayState);
                         final int newScreenState = toViewScreenState(newDisplayState);
@@ -867,6 +870,19 @@
         }
     };
 
+    void pokeDrawLockIfNeeded() {
+        final int displayState = mAttachInfo.mDisplayState;
+        if (mView != null && mAdded && mTraversalScheduled
+                && (displayState == Display.STATE_DOZE
+                        || displayState == Display.STATE_DOZE_SUSPEND)) {
+            try {
+                mWindowSession.pokeDrawLock(mWindow);
+            } catch (RemoteException ex) {
+                // System server died, oh well.
+            }
+        }
+    }
+
     @Override
     public void requestFitSystemWindows() {
         checkThread();
@@ -1041,6 +1057,7 @@
                 scheduleConsumeBatchedInput();
             }
             notifyRendererOfFramePending();
+            pokeDrawLockIfNeeded();
         }
     }
 
@@ -1342,7 +1359,7 @@
 
         boolean insetsChanged = false;
 
-        boolean layoutRequested = mLayoutRequested && !mStopped;
+        boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
         if (layoutRequested) {
 
             final Resources res = mView.getContext().getResources();
@@ -1513,6 +1530,7 @@
                         // to resume them
                         mDirty.set(0, 0, mWidth, mHeight);
                     }
+                    mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
                 }
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
@@ -1774,7 +1792,7 @@
                 }
             }
 
-            if (!mStopped) {
+            if (!mStopped || mReportNextDraw) {
                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                         (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
@@ -1847,7 +1865,7 @@
             }
         }
 
-        final boolean didLayout = layoutRequested && !mStopped;
+        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
         boolean triggerGlobalLayoutListener = didLayout
                 || mAttachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
@@ -2516,6 +2534,9 @@
             }
         }
 
+        mAttachInfo.mDrawingTime =
+                mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
+
         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                 // If accessibility focus moved, always invalidate the root.
@@ -2635,7 +2656,6 @@
 
             dirty.setEmpty();
             mIsAnimating = false;
-            attachInfo.mDrawingTime = SystemClock.uptimeMillis();
             mView.mPrivateFlags |= View.PFLAG_DRAWN;
 
             if (DEBUG_DRAW) {
@@ -3080,17 +3100,6 @@
         return (theParent instanceof ViewGroup) && isViewDescendantOf((View) theParent, parent);
     }
 
-    private static void forceLayout(View view) {
-        view.forceLayout();
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-            final int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                forceLayout(group.getChildAt(i));
-            }
-        }
-    }
-
     private final static int MSG_INVALIDATE = 1;
     private final static int MSG_INVALIDATE_RECT = 2;
     private final static int MSG_DIE = 3;
@@ -3224,10 +3233,6 @@
                         mReportNextDraw = true;
                     }
 
-                    if (mView != null) {
-                        forceLayout(mView);
-                    }
-
                     requestLayout();
                 }
                 break;
@@ -3242,9 +3247,6 @@
                     mWinFrame.top = t;
                     mWinFrame.bottom = t + h;
 
-                    if (mView != null) {
-                        forceLayout(mView);
-                    }
                     requestLayout();
                 }
                 break;
@@ -5789,6 +5791,16 @@
             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                     mPendingInputEventCount);
 
+            long eventTime = q.mEvent.getEventTimeNano();
+            long oldestEventTime = eventTime;
+            if (q.mEvent instanceof MotionEvent) {
+                MotionEvent me = (MotionEvent)q.mEvent;
+                if (me.getHistorySize() > 0) {
+                    oldestEventTime = me.getHistoricalEventTimeNano(0);
+                }
+            }
+            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
+
             deliverInputEvent(q);
         }
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 279627a..1cebe3f 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -492,7 +492,7 @@
         }
     }
 
-    public void dumpGfxInfo(FileDescriptor fd) {
+    public void dumpGfxInfo(FileDescriptor fd, String[] args) {
         FileOutputStream fout = new FileOutputStream(fd);
         PrintWriter pw = new FastPrintWriter(fout);
         try {
@@ -509,7 +509,7 @@
                     HardwareRenderer renderer =
                             root.getView().mAttachInfo.mHardwareRenderer;
                     if (renderer != null) {
-                        renderer.dumpGfxInfo(pw, fd);
+                        renderer.dumpGfxInfo(pw, fd, args);
                     }
                 }
 
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index f557b97..7b4640b 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -20,7 +20,7 @@
 import android.graphics.Region;
 import android.hardware.display.DisplayManagerInternal;
 import android.os.IBinder;
-import android.os.IRemoteCallback;
+import android.view.animation.Animation;
 
 import java.util.List;
 
@@ -85,6 +85,41 @@
     }
 
     /**
+     * Abstract class to be notified about {@link com.android.server.wm.AppTransition} events. Held
+     * as an abstract class so a listener only needs to implement the methods of its interest.
+     */
+    public static abstract class AppTransitionListener {
+
+        /**
+         * Called when an app transition is being setup and about to be executed.
+         */
+        public void onAppTransitionPendingLocked() {}
+
+        /**
+         * Called when a pending app transition gets cancelled.
+         */
+        public void onAppTransitionCancelledLocked() {}
+
+        /**
+         * Called when an app transition gets started
+         *
+         * @param openToken the token for the opening app
+         * @param closeToken the token for the closing app
+         * @param openAnimation the animation for the opening app
+         * @param closeAnimation the animation for the closing app
+         */
+        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
+                Animation openAnimation, Animation closeAnimation) {}
+
+        /**
+         * Called when an app transition is finished running.
+         *
+         * @param token the token for app whose transition has finished
+         */
+        public void onAppTransitionFinishedLocked(IBinder token) {}
+    }
+
+    /**
      * Request that the window manager call
      * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
      * within a surface transaction at a later time.
@@ -189,4 +224,11 @@
      * @param removeWindows Whether to also remove the windows associated with the token.
      */
     public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows);
+
+    /**
+     * Registers a listener to be notified about app transition events.
+     *
+     * @param listener The listener to register.
+     */
+    public abstract void registerAppTransitionListener(AppTransitionListener listener);
 }
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 1671faa..c2f3777 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.inputmethod.InputMethodUtils;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -379,7 +381,7 @@
      */
     public CharSequence getDisplayName(
             Context context, String packageName, ApplicationInfo appInfo) {
-        final Locale locale = constructLocaleFromString(mSubtypeLocale);
+        final Locale locale = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
         final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
         if (mSubtypeNameResId == 0) {
             return localeStr;
@@ -503,22 +505,6 @@
         }
     };
 
-    private static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr))
-            return null;
-        String[] localeParams = localeStr.split("_", 3);
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
     private static int hashCodeInternal(String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
             boolean isAsciiCapable) {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 78344ac..79ad6e3 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -423,8 +423,8 @@
         }
 
         if (track != null) {
-            track.setBounds(0, trackOffset, w - mPaddingRight - mPaddingLeft,
-                    h - mPaddingBottom - trackOffset - mPaddingTop);
+            final int trackWidth = w - mPaddingRight - mPaddingLeft;
+            track.setBounds(0, trackOffset, trackWidth, trackOffset + trackHeight);
         }
 
         if (thumb != null) {
@@ -472,7 +472,6 @@
 
         final Drawable background = getBackground();
         if (background != null) {
-            final Rect bounds = thumb.getBounds();
             final int offsetX = mPaddingLeft - mThumbOffset;
             final int offsetY = mPaddingTop;
             background.setHotspotBounds(left + offsetX, top + offsetY,
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4752594..1ba11da 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -50,6 +50,7 @@
 import android.inputmethodservice.ExtractEditText;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.DynamicLayout;
@@ -118,15 +119,18 @@
  */
 public class Editor {
     private static final String TAG = "Editor";
-    static final boolean DEBUG_UNDO = false;
+    private static final boolean DEBUG_UNDO = false;
 
     static final int BLINK = 500;
     private static final float[] TEMP_POSITION = new float[2];
     private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
+    // Tag used when the Editor maintains its own separate UndoManager.
+    private static final String UNDO_OWNER_TAG = "Editor";
 
-    UndoManager mUndoManager;
-    UndoOwner mUndoOwner;
-    InputFilter mUndoInputFilter;
+    // Each Editor manages its own undo stack.
+    private final UndoManager mUndoManager = new UndoManager();
+    private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    final InputFilter mUndoInputFilter = new UndoInputFilter(this);
 
     // Cursor Controllers.
     InsertionPointCursorController mInsertionPointCursorController;
@@ -222,6 +226,39 @@
 
     Editor(TextView textView) {
         mTextView = textView;
+        // Synchronize the filter list, which places the undo input filter at the end.
+        mTextView.setFilters(mTextView.getFilters());
+    }
+
+    ParcelableParcel saveInstanceState() {
+        // For now there is only undo state.
+        return (ParcelableParcel) mUndoManager.saveInstanceState();
+    }
+
+    void restoreInstanceState(ParcelableParcel state) {
+        mUndoManager.restoreInstanceState(state);
+        // Re-associate this object as the owner of undo state.
+        mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    }
+
+    boolean canUndo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mUndoManager.countUndos(owners) > 0;
+    }
+
+    boolean canRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mUndoManager.countRedos(owners) > 0;
+    }
+
+    void undo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.undo(owners, 1);  // Undo 1 action.
+    }
+
+    void redo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.redo(owners, 1);  // Redo 1 action.
     }
 
     void onAttachedToWindow() {
@@ -1706,7 +1743,7 @@
 
     /**
      * Called by the framework in response to a text auto-correction (such as fixing a typo using a
-     * a dictionnary) from the current input method, provided by it calling
+     * a dictionary) from the current input method, provided by it calling
      * {@link InputConnection#commitCorrection} InputConnection.commitCorrection()}. The default
      * implementation flashes the background of the corrected word to provide feedback to the user.
      *
@@ -4161,8 +4198,19 @@
         int mChangedStart, mChangedEnd, mChangedDelta;
     }
 
+    /**
+     * @return True iff (start, end) is a valid range within the text.
+     */
+    private static boolean isValidRange(CharSequence text, int start, int end) {
+        return 0 <= start && start <= end && end <= text.length();
+    }
+
+    /**
+     * An InputFilter that monitors text input to maintain undo history. It does not modify the
+     * text being typed (and hence always returns null from the filter() method).
+     */
     public static class UndoInputFilter implements InputFilter {
-        final Editor mEditor;
+        private final Editor mEditor;
 
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
@@ -4172,92 +4220,123 @@
         public CharSequence filter(CharSequence source, int start, int end,
                 Spanned dest, int dstart, int dend) {
             if (DEBUG_UNDO) {
-                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ")");
-                Log.d(TAG, "filter: dest=" + dest + " (" + dstart + "-" + dend + ")");
+                Log.d(TAG, "filter: source=" + source + " (" + start + "-" + end + ") " +
+                        "dest=" + dest + " (" + dstart + "-" + dend + ")");
             }
             final UndoManager um = mEditor.mUndoManager;
             if (um.isInUndo()) {
-                if (DEBUG_UNDO) Log.d(TAG, "*** skipping, currently performing undo/redo");
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping, currently performing undo/redo");
                 return null;
             }
 
+            // Text filters run before input operations are applied. However, some input operations
+            // are invalid and will throw exceptions when applied. This is common in tests. Don't
+            // attempt to undo invalid operations.
+            if (!isValidRange(source, start, end) || !isValidRange(dest, dstart, dend)) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: invalid op");
+                return null;
+            }
+
+            // Earlier filters can rewrite input to be a no-op, for example due to a length limit
+            // on an input field. Skip no-op changes.
+            if (start == end && dstart == dend) {
+                if (DEBUG_UNDO) Log.d(TAG, "filter: skipping no-op");
+                return null;
+            }
+
+            // Build a new operation with all the information from this edit.
+            EditOperation edit = new EditOperation(mEditor, source, start, end, dest, dstart, dend);
+
+            // Fetch the last edit operation and attempt to merge in the new edit.
             um.beginUpdate("Edit text");
-            TextModifyOperation op = um.getLastOperation(
-                    TextModifyOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
-            if (op != null) {
-                if (DEBUG_UNDO) Log.d(TAG, "Last op: range=(" + op.mRangeStart + "-" + op.mRangeEnd
-                        + "), oldText=" + op.mOldText);
-                // See if we can continue modifying this operation.
-                if (op.mOldText == null) {
-                    // The current operation is an add...  are we adding more?  We are adding
-                    // more if we are either appending new text to the end of the last edit or
-                    // completely replacing some or all of the last edit.
-                    if (start < end && ((dstart >= op.mRangeStart && dend <= op.mRangeEnd)
-                            || (dstart == op.mRangeEnd && dend == op.mRangeEnd))) {
-                        op.mRangeEnd = dstart + (end-start);
-                        um.endUpdate();
-                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, mRangeEnd="
-                                + op.mRangeEnd);
-                        return null;
-                    }
-                } else {
-                    // The current operation is a delete...  can we delete more?
-                    if (start == end && dend == op.mRangeStart-1) {
-                        SpannableStringBuilder str;
-                        if (op.mOldText instanceof SpannableString) {
-                            str = (SpannableStringBuilder)op.mOldText;
-                        } else {
-                            str = new SpannableStringBuilder(op.mOldText);
-                        }
-                        str.insert(0, dest, dstart, dend);
-                        op.mRangeStart = dstart;
-                        op.mOldText = str;
-                        um.endUpdate();
-                        if (DEBUG_UNDO) Log.d(TAG, "*** merging with last op, range=("
-                                + op.mRangeStart + "-" + op.mRangeEnd
-                                + "), oldText=" + op.mOldText);
-                        return null;
-                    }
-                }
-
-                // Couldn't add to the current undo operation, need to start a new
-                // undo state for a new undo operation.
-                um.commitState(null);
-                um.setUndoLabel("Edit text");
-            }
-
-            // Create a new undo state reflecting the operation being performed.
-            op = new TextModifyOperation(mEditor.mUndoOwner);
-            op.mRangeStart = dstart;
-            if (start < end) {
-                op.mRangeEnd = dstart + (end-start);
+            EditOperation lastEdit = um.getLastOperation(
+                  EditOperation.class, mEditor.mUndoOwner, UndoManager.MERGE_MODE_UNIQUE);
+            if (lastEdit == null) {
+                // Add this as the first edit.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: adding first op " + edit);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
+            } else if (lastEdit.mergeWith(edit)) {
+                // Merge succeeded, nothing else to do.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: merge succeeded, created " + lastEdit);
             } else {
-                op.mRangeEnd = dstart;
+                // Could not merge with the last edit, so commit the last edit and add this edit.
+                if (DEBUG_UNDO) Log.d(TAG, "filter: merge failed, adding " + edit);
+                um.commitState(mEditor.mUndoOwner);
+                um.addOperation(edit, UndoManager.MERGE_MODE_NONE);
             }
-            if (dstart < dend) {
-                op.mOldText = dest.subSequence(dstart, dend);
-            }
-            if (DEBUG_UNDO) Log.d(TAG, "*** adding new op, range=(" + op.mRangeStart
-                    + "-" + op.mRangeEnd + "), oldText=" + op.mOldText);
-            um.addOperation(op, UndoManager.MERGE_MODE_NONE);
             um.endUpdate();
-            return null;
+            return null;  // Text not changed.
         }
     }
 
-    public static class TextModifyOperation extends UndoOperation<TextView> {
-        int mRangeStart, mRangeEnd;
-        CharSequence mOldText;
+    /**
+     * An operation to undo a single "edit" to a text view.
+     */
+    public static class EditOperation extends UndoOperation<Editor> {
+        private static final int TYPE_INSERT = 0;
+        private static final int TYPE_DELETE = 1;
+        private static final int TYPE_REPLACE = 2;
 
-        public TextModifyOperation(UndoOwner owner) {
-            super(owner);
+        private int mType;
+        private String mOldText;
+        private int mOldTextStart;
+        private String mNewText;
+        private int mNewTextStart;
+
+        private int mOldCursorPos;
+        private int mNewCursorPos;
+
+        /**
+         * Constructs an edit operation from a text input operation that replaces the range
+         * (dstart, dend) of dest with (start, end) of source. See {@link InputFilter#filter}.
+         */
+        public EditOperation(Editor editor, CharSequence source, int start, int end,
+                Spanned dest, int dstart, int dend) {
+            super(editor.mUndoOwner);
+
+            mOldText = dest.subSequence(dstart, dend).toString();
+            mNewText = source.subSequence(start, end).toString();
+
+            // Determine the type of the edit and store where it occurred. Avoid storing
+            // irrevelant data (e.g. mNewTextStart for a delete) because that makes the
+            // merging logic more complex (e.g. merging deletes could lead to mNewTextStart being
+            // outside the bounds of the final text).
+            if (mNewText.length() > 0 && mOldText.length() == 0) {
+                mType = TYPE_INSERT;
+                mNewTextStart = dstart;
+            } else if (mNewText.length() == 0 && mOldText.length() > 0) {
+                mType = TYPE_DELETE;
+                mOldTextStart = dstart;
+            } else {
+                mType = TYPE_REPLACE;
+                mOldTextStart = mNewTextStart = dstart;
+            }
+
+            // Store cursor data.
+            mOldCursorPos = editor.mTextView.getSelectionStart();
+            mNewCursorPos = dstart + (end - start);
         }
 
-        public TextModifyOperation(Parcel src, ClassLoader loader) {
+        public EditOperation(Parcel src, ClassLoader loader) {
             super(src, loader);
-            mRangeStart = src.readInt();
-            mRangeEnd = src.readInt();
-            mOldText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(src);
+            mType = src.readInt();
+            mOldText = src.readString();
+            mOldTextStart = src.readInt();
+            mNewText = src.readString();
+            mNewTextStart = src.readInt();
+            mOldCursorPos = src.readInt();
+            mNewCursorPos = src.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(mType);
+            dest.writeString(mOldText);
+            dest.writeInt(mOldTextStart);
+            dest.writeString(mNewText);
+            dest.writeInt(mNewTextStart);
+            dest.writeInt(mOldCursorPos);
+            dest.writeInt(mNewCursorPos);
         }
 
         @Override
@@ -4266,59 +4345,139 @@
 
         @Override
         public void undo() {
-            swapText();
+            if (DEBUG_UNDO) Log.d(TAG, "undo");
+            // Remove the new text and insert the old.
+            modifyText(mNewTextStart, getNewTextEnd(), mOldText, mOldTextStart, mOldCursorPos);
         }
 
         @Override
         public void redo() {
-            swapText();
+            if (DEBUG_UNDO) Log.d(TAG, "redo");
+            // Remove the old text and insert the new.
+            modifyText(mOldTextStart, getOldTextEnd(), mNewText, mNewTextStart, mNewCursorPos);
         }
 
-        private void swapText() {
-            // Both undo and redo involves swapping the contents of the range
-            // in the text view with our local text.
-            TextView tv = getOwnerData();
-            Editable editable = (Editable)tv.getText();
-            CharSequence curText;
-            if (mRangeStart >= mRangeEnd) {
-                curText = null;
-            } else {
-                curText = editable.subSequence(mRangeStart, mRangeEnd);
+        /**
+         * Attempts to merge this existing operation with a new edit.
+         * @param edit The new edit operation.
+         * @return If the merge succeeded, returns true. Otherwise returns false and leaves this
+         * object unchanged.
+         */
+        private boolean mergeWith(EditOperation edit) {
+            switch (mType) {
+                case TYPE_INSERT:
+                    return mergeInsertWith(edit);
+                case TYPE_DELETE:
+                    return mergeDeleteWith(edit);
+                case TYPE_REPLACE:
+                    return mergeReplaceWith(edit);
+                default:
+                    return false;
             }
-            if (DEBUG_UNDO) {
-                Log.d(TAG, "Swap: range=(" + mRangeStart + "-" + mRangeEnd
-                        + "), oldText=" + mOldText);
-                Log.d(TAG, "Swap: curText=" + curText);
+        }
+
+        private boolean mergeInsertWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "mergeInsertWith " + edit);
+            // Only merge continuous insertions.
+            if (edit.mType != TYPE_INSERT) {
+                return false;
             }
-            if (mOldText == null) {
-                editable.delete(mRangeStart, mRangeEnd);
-                mRangeEnd = mRangeStart;
-            } else {
-                editable.replace(mRangeStart, mRangeEnd, mOldText);
-                mRangeEnd = mRangeStart + mOldText.length();
+            // Only merge insertions that are contiguous.
+            if (getNewTextEnd() != edit.mNewTextStart) {
+                return false;
             }
-            mOldText = curText;
+            mNewText += edit.mNewText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        // TODO: Support forward delete.
+        private boolean mergeDeleteWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "mergeDeleteWith " + edit);
+            // Only merge continuous deletes.
+            if (edit.mType != TYPE_DELETE) {
+                return false;
+            }
+            // Only merge deletions that are contiguous.
+            if (mOldTextStart != edit.getOldTextEnd()) {
+                return false;
+            }
+            mOldTextStart = edit.mOldTextStart;
+            mOldText = edit.mOldText + mOldText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        private boolean mergeReplaceWith(EditOperation edit) {
+            if (DEBUG_UNDO) Log.d(TAG, "mergeReplaceWith " + edit);
+            // Replacements can merge only with adjacent inserts and adjacent replacements.
+            if (edit.mType == TYPE_DELETE ||
+                    getNewTextEnd() != edit.mOldTextStart ||
+                    edit.mOldTextStart != edit.mNewTextStart) {
+                return false;
+            }
+            mOldText += edit.mOldText;
+            mNewText += edit.mNewText;
+            mNewCursorPos = edit.mNewCursorPos;
+            return true;
+        }
+
+        private int getNewTextEnd() {
+            return mNewTextStart + mNewText.length();
+        }
+
+        private int getOldTextEnd() {
+            return mOldTextStart + mOldText.length();
+        }
+
+        private void modifyText(int deleteFrom, int deleteTo, CharSequence newText,
+                int newTextInsertAt, int newCursorPos) {
+            Editor editor = getOwnerData();
+            Editable text = (Editable) editor.mTextView.getText();
+            // Apply the edit if it is still valid.
+            if (isValidRange(text, deleteFrom, deleteTo) &&
+                    newTextInsertAt <= text.length() - (deleteTo - deleteFrom)) {
+                if (deleteFrom != deleteTo) {
+                    text.delete(deleteFrom, deleteTo);
+                }
+                if (newText.length() != 0) {
+                    text.insert(newTextInsertAt, newText);
+                }
+            }
+            // Restore the cursor position.
+            // TODO: Select all the text that was undone.
+            if (newCursorPos <= text.length()) {
+                Selection.setSelection(text, newCursorPos);
+            }
         }
 
         @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mRangeStart);
-            dest.writeInt(mRangeEnd);
-            TextUtils.writeToParcel(mOldText, dest, flags);
+        public String toString() {
+            return "EditOperation: [" +
+                    "mType=" + mType + ", " +
+                    "mOldText=" + mOldText + ", " +
+                    "mOldTextStart=" + mOldTextStart + ", " +
+                    "mNewText=" + mNewText + ", " +
+                    "mNewTextStart=" + mNewTextStart + ", " +
+                    "mOldCursorPos=" + mOldCursorPos + ", " +
+                    "mNewCursorPos=" + mNewCursorPos + "]";
         }
 
-        public static final Parcelable.ClassLoaderCreator<TextModifyOperation> CREATOR
-                = new Parcelable.ClassLoaderCreator<TextModifyOperation>() {
-            public TextModifyOperation createFromParcel(Parcel in) {
-                return new TextModifyOperation(in, null);
+        public static final Parcelable.ClassLoaderCreator<EditOperation> CREATOR
+                = new Parcelable.ClassLoaderCreator<EditOperation>() {
+            @Override
+            public EditOperation createFromParcel(Parcel in) {
+                return new EditOperation(in, null);
             }
 
-            public TextModifyOperation createFromParcel(Parcel in, ClassLoader loader) {
-                return new TextModifyOperation(in, loader);
+            @Override
+            public EditOperation createFromParcel(Parcel in, ClassLoader loader) {
+                return new EditOperation(in, loader);
             }
 
-            public TextModifyOperation[] newArray(int size) {
-                return new TextModifyOperation[size];
+            @Override
+            public EditOperation[] newArray(int size) {
+                return new EditOperation[size];
             }
         };
     }
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 406a274..03878fc 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -401,36 +401,49 @@
      * traverse layer and state list drawables.
      */
     private Drawable tileify(Drawable drawable, boolean clip) {
+        // TODO: This is a terrible idea that potentially destroys any drawable
+        // that extends any of these classes. We *really* need to remove this.
 
         if (drawable instanceof LayerDrawable) {
-            LayerDrawable background = (LayerDrawable) drawable;
-            final int N = background.getNumberOfLayers();
-            Drawable[] outDrawables = new Drawable[N];
+            final LayerDrawable orig = (LayerDrawable) drawable;
+            final int N = orig.getNumberOfLayers();
+            final Drawable[] outDrawables = new Drawable[N];
 
             for (int i = 0; i < N; i++) {
-                int id = background.getId(i);
-                outDrawables[i] = tileify(background.getDrawable(i),
+                final int id = orig.getId(i);
+                outDrawables[i] = tileify(orig.getDrawable(i),
                         (id == R.id.progress || id == R.id.secondaryProgress));
             }
 
-            LayerDrawable newBg = new LayerDrawable(outDrawables);
-
+            final LayerDrawable clone = new LayerDrawable(outDrawables);
             for (int i = 0; i < N; i++) {
-                newBg.setId(i, background.getId(i));
+                clone.setId(i, orig.getId(i));
+                clone.setLayerGravity(i, orig.getLayerGravity(i));
+                clone.setLayerWidth(i, orig.getLayerWidth(i));
+                clone.setLayerHeight(i, orig.getLayerHeight(i));
+                clone.setLayerInsetLeft(i, orig.getLayerInsetLeft(i));
+                clone.setLayerInsetRight(i, orig.getLayerInsetRight(i));
+                clone.setLayerInsetTop(i, orig.getLayerInsetTop(i));
+                clone.setLayerInsetBottom(i, orig.getLayerInsetBottom(i));
+                clone.setLayerInsetStart(i, orig.getLayerInsetStart(i));
+                clone.setLayerInsetEnd(i, orig.getLayerInsetEnd(i));
             }
 
-            return newBg;
+            return clone;
+        }
 
-        } else if (drawable instanceof StateListDrawable) {
-            StateListDrawable in = (StateListDrawable) drawable;
-            StateListDrawable out = new StateListDrawable();
-            int numStates = in.getStateCount();
-            for (int i = 0; i < numStates; i++) {
+        if (drawable instanceof StateListDrawable) {
+            final StateListDrawable in = (StateListDrawable) drawable;
+            final StateListDrawable out = new StateListDrawable();
+            final int N = in.getStateCount();
+            for (int i = 0; i < N; i++) {
                 out.addState(in.getStateSet(i), tileify(in.getStateDrawable(i), clip));
             }
-            return out;
 
-        } else if (drawable instanceof BitmapDrawable) {
+            return out;
+        }
+
+        if (drawable instanceof BitmapDrawable) {
             final BitmapDrawable bitmap = (BitmapDrawable) drawable;
             final Bitmap tileBitmap = bitmap.getBitmap();
             if (mSampleTile == null) {
@@ -1648,7 +1661,7 @@
             // rotates properly in its animation
             final int saveCount = canvas.save();
 
-            if(isLayoutRtl() && mMirrorForRtl) {
+            if (isLayoutRtl() && mMirrorForRtl) {
                 canvas.translate(getWidth() - mPaddingRight, mPaddingTop);
                 canvas.scale(-1.0f, 1.0f);
             } else {
@@ -1680,20 +1693,23 @@
 
     @Override
     protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        Drawable d = mCurrentDrawable;
-
         int dw = 0;
         int dh = 0;
+
+        final Drawable d = mCurrentDrawable;
         if (d != null) {
             dw = Math.max(mMinWidth, Math.min(mMaxWidth, d.getIntrinsicWidth()));
             dh = Math.max(mMinHeight, Math.min(mMaxHeight, d.getIntrinsicHeight()));
         }
+
         updateDrawableState();
+
         dw += mPaddingLeft + mPaddingRight;
         dh += mPaddingTop + mPaddingBottom;
 
-        setMeasuredDimension(resolveSizeAndState(dw, widthMeasureSpec, 0),
-                resolveSizeAndState(dh, heightMeasureSpec, 0));
+        final int measuredWidth = resolveSizeAndState(dw, widthMeasureSpec, 0);
+        final int measuredHeight = resolveSizeAndState(dh, heightMeasureSpec, 0);
+        setMeasuredDimension(measuredWidth, measuredHeight);
     }
 
     @Override
@@ -1703,7 +1719,7 @@
     }
 
     private void updateDrawableState() {
-        int[] state = getDrawableState();
+        final int[] state = getDrawableState();
 
         if (mProgressDrawable != null && mProgressDrawable.isStateful()) {
             mProgressDrawable.setState(state);
diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java
index 4b061d3..dc4d932 100644
--- a/core/java/android/widget/RadialTimePickerView.java
+++ b/core/java/android/widget/RadialTimePickerView.java
@@ -43,7 +43,6 @@
 import android.view.HapticFeedbackConstants;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
@@ -63,12 +62,6 @@
 public class RadialTimePickerView extends View {
     private static final String TAG = "RadialTimePickerView";
 
-    private static final boolean DEBUG = false;
-
-    private static final int DEBUG_COLOR = 0x20FF0000;
-    private static final int DEBUG_TEXT_COLOR = 0x60FF0000;
-    private static final int DEBUG_STROKE_WIDTH = 2;
-
     private static final int HOURS = 0;
     private static final int MINUTES = 1;
     private static final int HOURS_INNER = 2;
@@ -93,8 +86,6 @@
     private static final int[] HOURS_NUMBERS_24 = {0, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23};
     private static final int[] MINUTES_NUMBERS = {0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55};
 
-    private static final int CENTER_RADIUS = 2;
-
     private static final int FADE_OUT_DURATION = 500;
     private static final int FADE_IN_DURATION = 500;
 
@@ -135,11 +126,12 @@
     private final IntHolder[][] mAlphaSelector = new IntHolder[2][3];
 
     private final Paint mPaintBackground = new Paint();
-    private final Paint mPaintDebug = new Paint();
 
     private final Typeface mTypeface;
 
-    private final float[] mTextSize = new float[2];
+    private final ColorStateList[] mTextColor = new ColorStateList[3];
+    private final int[] mTextSize = new int[3];
+    private final int[] mTextInset = new int[3];
 
     private final float[][] mOuterTextX = new float[2][12];
     private final float[][] mOuterTextY = new float[2][12];
@@ -147,22 +139,14 @@
     private final float[] mInnerTextX = new float[12];
     private final float[] mInnerTextY = new float[12];
 
-    private final float[] mNumbersRadiusMultiplier = new float[3];
-
-    private final float[] mTextSizeMultiplier = new float[3];
-
     private final int[] mLineLength = new int[3];
-    private final int[] mSelectionRadius = new int[3];
-    private final float mSelectionRadiusMultiplier;
     private final int[] mSelectionDegrees = new int[3];
 
-    private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<Animator>();
-    private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<Animator>();
+    private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<>();
+    private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<>();
 
     private final RadialPickerTouchHelper mTouchHelper;
 
-    private ColorStateList mNumbersTextColor;
-
     private boolean mIs24HourMode;
     private boolean mShowHours;
 
@@ -172,9 +156,13 @@
      */
     private boolean mIsOnInnerCircle;
 
-    private float mXCenter;
-    private float mYCenter;
-    private float mCircleRadius;
+    private int mSelectorRadius;
+    private int mSelectorDotRadius;
+    private int mCenterDotRadius;
+
+    private int mXCenter;
+    private int mYCenter;
+    private int mCircleRadius;
 
     private int mMinHypotenuseForInnerNumber;
     private int mMaxHypotenuseForOuterNumber;
@@ -186,7 +174,8 @@
     private AnimatorSet mTransition;
 
     private int mAmOrPm;
-    private int mDisabledAlpha;
+
+    private float mDisabledAlpha;
 
     private OnValueSelectedListener mListener;
 
@@ -313,7 +302,7 @@
         // Pull disabled alpha from theme.
         final TypedValue outValue = new TypedValue();
         context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true);
-        mDisabledAlpha = (int) (outValue.getFloat() * 255 + 0.5f);
+        mDisabledAlpha = outValue.getFloat();
 
         // process style attributes
         final Resources res = getResources();
@@ -332,8 +321,9 @@
             }
         }
 
-        mNumbersTextColor = a.getColorStateList(
-                R.styleable.TimePicker_numbersTextColor);
+        mTextColor[HOURS] = a.getColorStateList(R.styleable.TimePicker_numbersTextColor);
+        mTextColor[HOURS_INNER] = a.getColorStateList(R.styleable.TimePicker_numbersInnerTextColor);
+        mTextColor[MINUTES] = mTextColor[HOURS];
 
         mPaint[HOURS] = new Paint();
         mPaint[HOURS].setAntiAlias(true);
@@ -351,8 +341,8 @@
         mPaintCenter.setColor(selectorActivatedColor);
         mPaintCenter.setAntiAlias(true);
 
-        final int textActivatedColor = mNumbersTextColor.getColorForState(
-                StateSet.get(StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED), 0);
+        final int[] activatedStateSet = StateSet.get(
+                StateSet.VIEW_STATE_ENABLED | StateSet.VIEW_STATE_ACTIVATED);
 
         mPaintSelector[HOURS][SELECTOR_CIRCLE] = new Paint();
         mPaintSelector[HOURS][SELECTOR_CIRCLE].setAntiAlias(true);
@@ -360,7 +350,8 @@
 
         mPaintSelector[HOURS][SELECTOR_DOT] = new Paint();
         mPaintSelector[HOURS][SELECTOR_DOT].setAntiAlias(true);
-        mColorSelector[HOURS][SELECTOR_DOT] = textActivatedColor;
+        mColorSelector[HOURS][SELECTOR_DOT] =
+                mTextColor[HOURS].getColorForState(activatedStateSet, 0);
 
         mPaintSelector[HOURS][SELECTOR_LINE] = new Paint();
         mPaintSelector[HOURS][SELECTOR_LINE].setAntiAlias(true);
@@ -373,7 +364,8 @@
 
         mPaintSelector[MINUTES][SELECTOR_DOT] = new Paint();
         mPaintSelector[MINUTES][SELECTOR_DOT].setAntiAlias(true);
-        mColorSelector[MINUTES][SELECTOR_DOT] = textActivatedColor;
+        mColorSelector[MINUTES][SELECTOR_DOT] =
+                mTextColor[MINUTES].getColorForState(activatedStateSet, 0);
 
         mPaintSelector[MINUTES][SELECTOR_LINE] = new Paint();
         mPaintSelector[MINUTES][SELECTOR_LINE].setAntiAlias(true);
@@ -384,13 +376,17 @@
                 context.getColor(R.color.timepicker_default_numbers_background_color_material)));
         mPaintBackground.setAntiAlias(true);
 
-        if (DEBUG) {
-            mPaintDebug.setColor(DEBUG_COLOR);
-            mPaintDebug.setAntiAlias(true);
-            mPaintDebug.setStrokeWidth(DEBUG_STROKE_WIDTH);
-            mPaintDebug.setStyle(Paint.Style.STROKE);
-            mPaintDebug.setTextAlign(Paint.Align.CENTER);
-        }
+        mSelectorRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_radius);
+        mSelectorDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_selector_dot_radius);
+        mCenterDotRadius = res.getDimensionPixelSize(R.dimen.timepicker_center_dot_radius);
+
+        mTextSize[HOURS] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_normal);
+        mTextSize[MINUTES] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_normal);
+        mTextSize[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_size_inner);
+
+        mTextInset[HOURS] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_normal);
+        mTextInset[MINUTES] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_normal);
+        mTextInset[HOURS_INNER] = res.getDimensionPixelSize(R.dimen.timepicker_text_inset_inner);
 
         mShowHours = true;
         mIs24HourMode = false;
@@ -407,8 +403,6 @@
         initHoursAndMinutesText();
         initData();
 
-        mSelectionRadiusMultiplier = res.getFloat(R.dimen.timepicker_selection_radius_multiplier);
-
         a.recycle();
 
         // Initial values
@@ -621,30 +615,6 @@
 
         mOuterTextMinutes = mMinutesTexts;
 
-        final Resources res = getResources();
-
-        if (mIs24HourMode) {
-            mNumbersRadiusMultiplier[HOURS] = res.getFloat(
-                    R.dimen.timepicker_numbers_radius_multiplier_outer);
-            mTextSizeMultiplier[HOURS] = res.getFloat(
-                    R.dimen.timepicker_text_size_multiplier_outer);
-
-            mNumbersRadiusMultiplier[HOURS_INNER] = res.getFloat(
-                    R.dimen.timepicker_numbers_radius_multiplier_inner);
-            mTextSizeMultiplier[HOURS_INNER] = res.getFloat(
-                    R.dimen.timepicker_text_size_multiplier_inner);
-        } else {
-            mNumbersRadiusMultiplier[HOURS] = res.getFloat(
-                    R.dimen.timepicker_numbers_radius_multiplier_normal);
-            mTextSizeMultiplier[HOURS] = res.getFloat(
-                    R.dimen.timepicker_text_size_multiplier_normal);
-        }
-
-        mNumbersRadiusMultiplier[MINUTES] = res.getFloat(
-                R.dimen.timepicker_numbers_radius_multiplier_normal);
-        mTextSizeMultiplier[MINUTES] = res.getFloat(
-                R.dimen.timepicker_text_size_multiplier_normal);
-
         final int hoursAlpha = mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT;
         mAlpha[HOURS].setValue(hoursAlpha);
         mAlphaSelector[HOURS][SELECTOR_CIRCLE].setValue(hoursAlpha);
@@ -668,96 +638,78 @@
         mYCenter = getHeight() / 2;
         mCircleRadius = Math.min(mXCenter, mYCenter);
 
-        mMinHypotenuseForInnerNumber = (int) (mCircleRadius
-                * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS];
-        mMaxHypotenuseForOuterNumber = (int) (mCircleRadius
-                * mNumbersRadiusMultiplier[HOURS]) + mSelectionRadius[HOURS];
-        mHalfwayHypotenusePoint = (int) (mCircleRadius
-                * ((mNumbersRadiusMultiplier[HOURS] + mNumbersRadiusMultiplier[HOURS_INNER]) / 2));
-
-        mTextSize[HOURS] = mCircleRadius * mTextSizeMultiplier[HOURS];
-        mTextSize[MINUTES] = mCircleRadius * mTextSizeMultiplier[MINUTES];
-
-        if (mIs24HourMode) {
-            mTextSize[HOURS_INNER] = mCircleRadius * mTextSizeMultiplier[HOURS_INNER];
-        }
+        mMinHypotenuseForInnerNumber = mCircleRadius - mTextInset[HOURS_INNER] - mSelectorRadius;
+        mMaxHypotenuseForOuterNumber = mCircleRadius - mTextInset[HOURS] - mSelectorRadius;
+        mHalfwayHypotenusePoint = mCircleRadius - (mTextInset[HOURS] + mTextInset[HOURS_INNER]) / 2;
 
         calculatePositionsHours();
         calculatePositionsMinutes();
 
-        mSelectionRadius[HOURS] = (int) (mCircleRadius * mSelectionRadiusMultiplier);
-        mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS];
-        mSelectionRadius[MINUTES] = (int) (mCircleRadius * mSelectionRadiusMultiplier);
-
         mTouchHelper.invalidateRoot();
     }
 
     @Override
     public void onDraw(Canvas canvas) {
-        if (!mInputEnabled) {
-            canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), mDisabledAlpha);
-        } else {
-            canvas.save();
-        }
+        final float alphaMod = mInputEnabled ? 1 : mDisabledAlpha;
 
         drawCircleBackground(canvas);
-
-        final int hoursAlpha = mAlpha[HOURS].getValue();
-        if (hoursAlpha > 0) {
-            // Draw the hour selector under the elements.
-            drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS, null);
-
-            // Draw outer hours.
-            drawTextElements(canvas, mTextSize[HOURS], mTypeface, mOuterTextHours,
-                    mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS], hoursAlpha,
-                    !mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
-
-            // Draw inner hours (12-23) for 24-hour time.
-            if (mIs24HourMode && mInnerTextHours != null) {
-                drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mInnerTextHours,
-                        mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha,
-                        mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
-            }
-        }
-
-        final int minutesAlpha = mAlpha[MINUTES].getValue();
-        if (minutesAlpha > 0) {
-            drawSelector(canvas, MINUTES, mSelectorPath);
-
-            // Exclude the selector region, then draw minutes with no
-            // activated states.
-            canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE);
-            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mOuterTextMinutes,
-                    mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], minutesAlpha,
-                    false, 0, false);
-            canvas.restore();
-
-            // Intersect the selector region, then draw minutes with only
-            // activated states.
-            canvas.save(Canvas.CLIP_SAVE_FLAG);
-            canvas.clipPath(mSelectorPath, Region.Op.INTERSECT);
-            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mOuterTextMinutes,
-                    mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES], minutesAlpha,
-                    true, mSelectionDegrees[MINUTES], true);
-            canvas.restore();
-        }
-
-        drawCenter(canvas);
-
-        if (DEBUG) {
-            drawDebug(canvas);
-        }
-
-        canvas.restore();
+        drawHours(canvas, alphaMod);
+        drawMinutes(canvas, alphaMod);
+        drawCenter(canvas, alphaMod);
     }
 
     private void drawCircleBackground(Canvas canvas) {
         canvas.drawCircle(mXCenter, mYCenter, mCircleRadius, mPaintBackground);
     }
 
-    private void drawCenter(Canvas canvas) {
-        canvas.drawCircle(mXCenter, mYCenter, CENTER_RADIUS, mPaintCenter);
+    private void drawHours(Canvas canvas, float alphaMod) {
+        final int hoursAlpha = (int) (mAlpha[HOURS].getValue() * alphaMod + 0.5f);
+        if (hoursAlpha > 0) {
+            // Draw the hour selector under the elements.
+            drawSelector(canvas, mIsOnInnerCircle ? HOURS_INNER : HOURS, null, alphaMod);
+
+            // Draw outer hours.
+            drawTextElements(canvas, mTextSize[HOURS], mTypeface, mTextColor[HOURS],
+                    mOuterTextHours, mOuterTextX[HOURS], mOuterTextY[HOURS], mPaint[HOURS],
+                    hoursAlpha, !mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
+
+            // Draw inner hours (12-23) for 24-hour time.
+            if (mIs24HourMode && mInnerTextHours != null) {
+                drawTextElements(canvas, mTextSize[HOURS_INNER], mTypeface, mTextColor[HOURS_INNER],
+                        mInnerTextHours, mInnerTextX, mInnerTextY, mPaint[HOURS], hoursAlpha,
+                        mIsOnInnerCircle, mSelectionDegrees[HOURS], false);
+            }
+        }
+    }
+
+    private void drawMinutes(Canvas canvas, float alphaMod) {
+        final int minutesAlpha = (int) (mAlpha[MINUTES].getValue() * alphaMod + 0.5f);
+        if (minutesAlpha > 0) {
+            drawSelector(canvas, MINUTES, mSelectorPath, alphaMod);
+
+            // Exclude the selector region, then draw minutes with no
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(mSelectorPath, Region.Op.DIFFERENCE);
+            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
+                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    minutesAlpha, false, 0, false);
+            canvas.restore();
+
+            // Intersect the selector region, then draw minutes with only
+            // activated states.
+            canvas.save(Canvas.CLIP_SAVE_FLAG);
+            canvas.clipPath(mSelectorPath, Region.Op.INTERSECT);
+            drawTextElements(canvas, mTextSize[MINUTES], mTypeface, mTextColor[MINUTES],
+                    mOuterTextMinutes, mOuterTextX[MINUTES], mOuterTextY[MINUTES], mPaint[MINUTES],
+                    minutesAlpha, true, mSelectionDegrees[MINUTES], true);
+            canvas.restore();
+        }
+    }
+
+    private void drawCenter(Canvas canvas, float alphaMod) {
+        mPaintCenter.setAlpha((int) (255 * alphaMod + 0.5f));
+        canvas.drawCircle(mXCenter, mYCenter, mCenterDotRadius, mPaintCenter);
     }
 
     private int getMultipliedAlpha(int argb, int alpha) {
@@ -766,9 +718,9 @@
 
     private final Path mSelectorPath = new Path();
 
-    private void drawSelector(Canvas canvas, int index, Path selectorPath) {
+    private void drawSelector(Canvas canvas, int index, Path selectorPath, float alphaMod) {
         // Calculate the current radius at which to place the selection circle.
-        mLineLength[index] = (int) (mCircleRadius * mNumbersRadiusMultiplier[index]);
+        mLineLength[index] = mCircleRadius - mTextInset[index];
 
         final double selectionRadians = Math.toRadians(mSelectionDegrees[index]);
 
@@ -781,16 +733,16 @@
 
         // Draw the selection circle
         color = mColorSelector[index % 2][SELECTOR_CIRCLE];
-        alpha = mAlphaSelector[index % 2][SELECTOR_CIRCLE].getValue();
+        alpha = (int) (mAlphaSelector[index % 2][SELECTOR_CIRCLE].getValue() * alphaMod + 0.5f);
         paint = mPaintSelector[index % 2][SELECTOR_CIRCLE];
         paint.setColor(color);
         paint.setAlpha(getMultipliedAlpha(color, alpha));
-        canvas.drawCircle(pointX, pointY, mSelectionRadius[index], paint);
+        canvas.drawCircle(pointX, pointY, mSelectorRadius, paint);
 
         // If needed, set up the clip path for later.
         if (selectorPath != null) {
             mSelectorPath.reset();
-            mSelectorPath.addCircle(pointX, pointY, mSelectionRadius[index], Path.Direction.CCW);
+            mSelectorPath.addCircle(pointX, pointY, mSelectorRadius, Path.Direction.CCW);
         }
 
         // Draw the dot if needed.
@@ -798,80 +750,35 @@
         if (shouldDrawDot) {
             // We're not on a direct tick
             color = mColorSelector[index % 2][SELECTOR_DOT];
-            alpha = mAlphaSelector[index % 2][SELECTOR_DOT].getValue();
+            alpha = (int) (mAlphaSelector[index % 2][SELECTOR_DOT].getValue() * alphaMod + 0.5f);
             paint = mPaintSelector[index % 2][SELECTOR_DOT];
             paint.setColor(color);
             paint.setAlpha(getMultipliedAlpha(color, alpha));
-            canvas.drawCircle(pointX, pointY, (mSelectionRadius[index] * 0.125f), paint);
+            canvas.drawCircle(pointX, pointY, mSelectorDotRadius, paint);
         }
 
-        // Shorten the line to only go to the edge of the selection circle.
-        final int lineLength = mLineLength[index] - mSelectionRadius[index];
-        pointX = mXCenter + (int) (lineLength * Math.sin(selectionRadians));
-        pointY = mYCenter - (int) (lineLength * Math.cos(selectionRadians));
+        // Shorten the line to only go from the edge of the center dot to the
+        // edge of the selection circle.
+        final double sin = Math.sin(selectionRadians);
+        final double cos = Math.cos(selectionRadians);
+        final int lineLength = mLineLength[index] - mSelectorRadius;
+        final int centerX = mXCenter + (int) (mCenterDotRadius * sin);
+        final int centerY = mYCenter - (int) (mCenterDotRadius * cos);
+        pointX = centerX + (int) (lineLength * sin);
+        pointY = centerY - (int) (lineLength * cos);
 
         // Draw the line
         color = mColorSelector[index % 2][SELECTOR_LINE];
-        alpha = mAlphaSelector[index % 2][SELECTOR_LINE].getValue();
+        alpha = (int) (mAlphaSelector[index % 2][SELECTOR_LINE].getValue() * alphaMod + 0.5f);
         paint = mPaintSelector[index % 2][SELECTOR_LINE];
         paint.setColor(color);
         paint.setAlpha(getMultipliedAlpha(color, alpha));
         canvas.drawLine(mXCenter, mYCenter, pointX, pointY, paint);
     }
 
-    private void drawDebug(Canvas canvas) {
-        // Draw outer numbers circle
-        final float outerRadius = mCircleRadius * mNumbersRadiusMultiplier[HOURS];
-        canvas.drawCircle(mXCenter, mYCenter, outerRadius, mPaintDebug);
-
-        // Draw inner numbers circle
-        final float innerRadius = mCircleRadius * mNumbersRadiusMultiplier[HOURS_INNER];
-        canvas.drawCircle(mXCenter, mYCenter, innerRadius, mPaintDebug);
-
-        // Draw outer background circle
-        canvas.drawCircle(mXCenter, mYCenter, mCircleRadius, mPaintDebug);
-
-        // Draw outer rectangle for circles
-        float left = mXCenter - outerRadius;
-        float top = mYCenter - outerRadius;
-        float right = mXCenter + outerRadius;
-        float bottom = mYCenter + outerRadius;
-        canvas.drawRect(left, top, right, bottom, mPaintDebug);
-
-        // Draw outer rectangle for background
-        left = mXCenter - mCircleRadius;
-        top = mYCenter - mCircleRadius;
-        right = mXCenter + mCircleRadius;
-        bottom = mYCenter + mCircleRadius;
-        canvas.drawRect(left, top, right, bottom, mPaintDebug);
-
-        // Draw outer view rectangle
-        canvas.drawRect(0, 0, getWidth(), getHeight(), mPaintDebug);
-
-        // Draw selected time
-        final String selected = String.format("%02d:%02d", getCurrentHour(), getCurrentMinute());
-
-        ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
-                ViewGroup.LayoutParams.WRAP_CONTENT);
-        TextView tv = new TextView(getContext());
-        tv.setLayoutParams(lp);
-        tv.setText(selected);
-        tv.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
-        Paint paint = tv.getPaint();
-        paint.setColor(DEBUG_TEXT_COLOR);
-
-        final int width = tv.getMeasuredWidth();
-
-        float height = paint.descent() - paint.ascent();
-        float x = mXCenter - width / 2;
-        float y = mYCenter + 1.5f * height;
-
-        canvas.drawText(selected, x, y, paint);
-    }
-
     private void calculatePositionsHours() {
         // Calculate the text positions
-        final float numbersRadius = mCircleRadius * mNumbersRadiusMultiplier[HOURS];
+        final float numbersRadius = mCircleRadius - mTextInset[HOURS];
 
         // Calculate the positions for the 12 numbers in the main circle.
         calculatePositions(mPaint[HOURS], numbersRadius, mXCenter, mYCenter,
@@ -879,9 +786,7 @@
 
         // If we have an inner circle, calculate those positions too.
         if (mIs24HourMode) {
-            final float innerNumbersRadius = mCircleRadius
-                    * mNumbersRadiusMultiplier[HOURS_INNER];
-
+            final int innerNumbersRadius = mCircleRadius - mTextInset[HOURS_INNER];
             calculatePositions(mPaint[HOURS], innerNumbersRadius, mXCenter, mYCenter,
                     mTextSize[HOURS_INNER], mInnerTextX, mInnerTextY);
         }
@@ -889,7 +794,7 @@
 
     private void calculatePositionsMinutes() {
         // Calculate the text positions
-        final float numbersRadius = mCircleRadius * mNumbersRadiusMultiplier[MINUTES];
+        final float numbersRadius = mCircleRadius - mTextInset[MINUTES];
 
         // Calculate the positions for the 12 numbers in the main circle.
         calculatePositions(mPaint[MINUTES], numbersRadius, mXCenter, mYCenter,
@@ -916,9 +821,9 @@
     /**
      * Draw the 12 text values at the positions specified by the textGrid parameters.
      */
-    private void drawTextElements(Canvas canvas, float textSize, Typeface typeface, String[] texts,
-            float[] textX, float[] textY, Paint paint, int alpha, boolean showActivated,
-            int activatedDegrees, boolean activatedOnly) {
+    private void drawTextElements(Canvas canvas, float textSize, Typeface typeface,
+            ColorStateList textColor, String[] texts, float[] textX, float[] textY, Paint paint,
+            int alpha, boolean showActivated, int activatedDegrees, boolean activatedOnly) {
         paint.setTextSize(textSize);
         paint.setTypeface(typeface);
 
@@ -935,7 +840,7 @@
 
             final int stateMask = StateSet.VIEW_STATE_ENABLED
                     | (showActivated && activated ? StateSet.VIEW_STATE_ACTIVATED : 0);
-            final int color = mNumbersTextColor.getColorForState(StateSet.get(stateMask), 0);
+            final int color = textColor.getColorForState(StateSet.get(stateMask), 0);
             paint.setColor(color);
             paint.setAlpha(getMultipliedAlpha(color, alpha));
 
@@ -1058,10 +963,9 @@
             }
         } else {
             final int index =  (mShowHours) ? HOURS : MINUTES;
-            final float length = (mCircleRadius * mNumbersRadiusMultiplier[index]);
+            final float length = (mCircleRadius - mTextInset[index]);
             final int distanceToNumber = (int) (hypotenuse - length);
-            final int maxAllowedDistance =
-                    (int) (mCircleRadius * (1 - mNumbersRadiusMultiplier[index]));
+            final int maxAllowedDistance = mTextInset[index];
             if (distanceToNumber < -maxAllowedDistance
                     || (constrainOutside && distanceToNumber > maxAllowedDistance)) {
                 return -1;
@@ -1431,18 +1335,18 @@
             if (type == TYPE_HOUR) {
                 final boolean innerCircle = mIs24HourMode && value > 0 && value <= 12;
                 if (innerCircle) {
-                    centerRadius = mCircleRadius * mNumbersRadiusMultiplier[HOURS_INNER];
-                    radius = mSelectionRadius[HOURS_INNER];
+                    centerRadius = mCircleRadius - mTextInset[HOURS_INNER];
+                    radius = mSelectorRadius;
                 } else {
-                    centerRadius = mCircleRadius * mNumbersRadiusMultiplier[HOURS];
-                    radius = mSelectionRadius[HOURS];
+                    centerRadius = mCircleRadius - mTextInset[HOURS];
+                    radius = mSelectorRadius;
                 }
 
                 degrees = getDegreesForHour(value);
             } else if (type == TYPE_MINUTE) {
-                centerRadius = mCircleRadius * mNumbersRadiusMultiplier[MINUTES];
+                centerRadius = mCircleRadius - mTextInset[MINUTES];
                 degrees = getDegreesForMinute(value);
-                radius = mSelectionRadius[MINUTES];
+                radius = mSelectorRadius;
             } else {
                 // This should never happen.
                 centerRadius = 0;
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 89b1d54..fef56b8 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -617,15 +617,17 @@
             }
         }
 
-        // Use the bottom-most view as the baseline.
+        // Use the bottom-most laid out view as the baseline.
         View baselineView = null;
         int baseline = 0;
         for (int i = 0; i < count; i++) {
             final View child = getChildAt(i);
-            final int childBaseline = child.getBaseline();
-            if (childBaseline >= baseline) {
-                baselineView = child;
-                baseline = childBaseline;
+            if (child.getVisibility() != GONE) {
+                final int childBaseline = child.getBaseline();
+                if (childBaseline >= baseline) {
+                    baselineView = child;
+                    baseline = childBaseline;
+                }
             }
         }
         mBaselineView = baselineView;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f33ef75..9297731 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -47,6 +47,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -1612,7 +1613,8 @@
      * @hide
      */
     public final UndoManager getUndoManager() {
-        return mEditor == null ? null : mEditor.mUndoManager;
+        // TODO: Consider supporting a global undo manager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -1630,22 +1632,12 @@
      * @hide
      */
     public final void setUndoManager(UndoManager undoManager, String tag) {
-        if (undoManager != null) {
-            createEditorIfNeeded();
-            mEditor.mUndoManager = undoManager;
-            mEditor.mUndoOwner = undoManager.getOwner(tag, this);
-            mEditor.mUndoInputFilter = new Editor.UndoInputFilter(mEditor);
-            if (!(mText instanceof Editable)) {
-                setText(mText, BufferType.EDITABLE);
-            }
-
-            setFilters((Editable) mText, mFilters);
-        } else if (mEditor != null) {
-            // XXX need to destroy all associated state.
-            mEditor.mUndoManager = null;
-            mEditor.mUndoOwner = null;
-            mEditor.mUndoInputFilter = null;
-        }
+        // TODO: Consider supporting a global undo manager. An implementation will need to:
+        // * createEditorIfNeeded()
+        // * Promote to BufferType.EDITABLE if needed.
+        // * Update the UndoManager and UndoOwner.
+        // Likewise it will need to be able to restore the default UndoManager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -3899,6 +3891,9 @@
 
             ss.error = getError();
 
+            if (mEditor != null) {
+                ss.editorState = mEditor.saveInstanceState();
+            }
             return ss;
         }
 
@@ -3968,6 +3963,11 @@
                 }
             });
         }
+
+        if (ss.editorState != null) {
+            createEditorIfNeeded();
+            mEditor.restoreInstanceState(ss.editorState);
+        }
     }
 
     /**
@@ -8375,14 +8375,19 @@
 
     @Override
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
-        final int filteredMetaState = event.getMetaState() & ~KeyEvent.META_CTRL_MASK;
-        if (KeyEvent.metaStateHasNoModifiers(filteredMetaState)) {
+        if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
+            // Handle Ctrl-only shortcuts.
             switch (keyCode) {
             case KeyEvent.KEYCODE_A:
                 if (canSelectText()) {
                     return onTextContextMenuItem(ID_SELECT_ALL);
                 }
                 break;
+            case KeyEvent.KEYCODE_Z:
+                if (canUndo()) {
+                    return onTextContextMenuItem(ID_UNDO);
+                }
+                break;
             case KeyEvent.KEYCODE_X:
                 if (canCut()) {
                     return onTextContextMenuItem(ID_CUT);
@@ -8399,6 +8404,15 @@
                 }
                 break;
             }
+        } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
+            // Handle Ctrl-Shift shortcuts.
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_Z:
+                    if (canRedo()) {
+                        return onTextContextMenuItem(ID_REDO);
+                    }
+                    break;
+            }
         }
         return super.onKeyShortcut(keyCode, event);
     }
@@ -8775,6 +8789,8 @@
     }
 
     static final int ID_SELECT_ALL = android.R.id.selectAll;
+    static final int ID_UNDO = android.R.id.undo;
+    static final int ID_REDO = android.R.id.redo;
     static final int ID_CUT = android.R.id.cut;
     static final int ID_COPY = android.R.id.copy;
     static final int ID_PASTE = android.R.id.paste;
@@ -8805,6 +8821,18 @@
                 selectAllText();
                 return true;
 
+            case ID_UNDO:
+                if (mEditor != null) {
+                    mEditor.undo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
+            case ID_REDO:
+                if (mEditor != null) {
+                    mEditor.redo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
             case ID_PASTE:
                 paste(min, max);
                 return true;
@@ -8934,7 +8962,17 @@
      * @hide
      */
     protected void stopSelectionActionMode() {
-        mEditor.stopSelectionActionMode();
+        if (mEditor != null) {
+            mEditor.stopSelectionActionMode();
+        }
+    }
+
+    boolean canUndo() {
+        return mEditor != null && mEditor.canUndo();
+    }
+
+    boolean canRedo() {
+        return mEditor != null && mEditor.canRedo();
     }
 
     boolean canCut() {
@@ -9304,6 +9342,7 @@
         CharSequence text;
         boolean frozenWithFocus;
         CharSequence error;
+        ParcelableParcel editorState;  // Optional state from Editor.
 
         SavedState(Parcelable superState) {
             super(superState);
@@ -9323,6 +9362,13 @@
                 out.writeInt(1);
                 TextUtils.writeToParcel(error, out, flags);
             }
+
+            if (editorState == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                editorState.writeToParcel(out, flags);
+            }
         }
 
         @Override
@@ -9358,6 +9404,10 @@
             if (in.readInt() != 0) {
                 error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             }
+
+            if (in.readInt() != 0) {
+                editorState = ParcelableParcel.CREATOR.createFromParcel(in);
+            }
         }
     }
 
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 05c7a5f..ed052af 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -91,6 +91,7 @@
     private int mInitialHourOfDay;
     private int mInitialMinute;
     private boolean mIs24HourView;
+    private boolean mIsAmPmAtStart;
 
     // For hardware IME input.
     private char mPlaceholderText;
@@ -284,24 +285,37 @@
     }
 
     private void updateHeaderAmPm() {
+
         if (mIs24HourView) {
             mAmPmLayout.setVisibility(View.GONE);
         } else {
             // Ensure that AM/PM layout is in the correct position.
             final String dateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, "hm");
-            final boolean amPmAtStart = dateTimePattern.startsWith("a");
-            final ViewGroup parent = (ViewGroup) mAmPmLayout.getParent();
-            final int targetIndex = amPmAtStart ? 0 : parent.getChildCount() - 1;
-            final int currentIndex = parent.indexOfChild(mAmPmLayout);
-            if (targetIndex != currentIndex) {
-                parent.removeView(mAmPmLayout);
-                parent.addView(mAmPmLayout, targetIndex);
-            }
+            final boolean isAmPmAtStart = dateTimePattern.startsWith("a");
+            setAmPmAtStart(isAmPmAtStart);
 
             updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM);
         }
     }
 
+    private void setAmPmAtStart(boolean isAmPmAtStart) {
+        if (mIsAmPmAtStart != isAmPmAtStart) {
+            mIsAmPmAtStart = isAmPmAtStart;
+
+            final RelativeLayout.LayoutParams params =
+                    (RelativeLayout.LayoutParams) mAmPmLayout.getLayoutParams();
+            if (isAmPmAtStart) {
+                params.removeRule(RelativeLayout.RIGHT_OF);
+                params.addRule(RelativeLayout.LEFT_OF, mHourView.getId());
+            } else {
+                params.removeRule(RelativeLayout.LEFT_OF);
+                params.addRule(RelativeLayout.RIGHT_OF, mMinuteView.getId());
+            }
+
+            mAmPmLayout.setLayoutParams(params);
+        }
+    }
+
     /**
      * Set the current hour.
      */
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 183527c..9aa36d3 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -35,6 +35,8 @@
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.TextServicesManager;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -409,6 +411,24 @@
         return false;
     }
 
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+
     public static boolean containsSubtypeOf(final InputMethodInfo imi,
             @Nullable final Locale locale, final boolean checkCountry, final String mode) {
         if (locale == null) {
@@ -418,15 +438,16 @@
         for (int i = 0; i < N; ++i) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(i);
             if (checkCountry) {
-                // TODO: Use {@link Locale#toLanguageTag()} and
-                // {@link Locale#forLanguageTag(languageTag)} instead.
-                if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
+                final Locale subtypeLocale = constructLocaleFromString(subtype.getLocale());
+                if (subtypeLocale == null ||
+                        !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) ||
+                        !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) {
                     continue;
                 }
             } else {
                 final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
                         subtype.getLocale()));
-                if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
+                if (!TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage())) {
                     continue;
                 }
             }
@@ -518,7 +539,8 @@
         return NOT_A_SUBTYPE_ID;
     }
 
-    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+    @VisibleForTesting
+    public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
             Resources res, InputMethodInfo imi) {
         final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
         final String systemLocale = res.getConfiguration().locale.toString();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 20bb95e..d0c7f8c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -94,7 +94,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 118 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -208,7 +208,7 @@
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
     final HistoryItem mHistoryAddTmp = new HistoryItem();
-    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap();
     String[] mReadHistoryStrings;
     int[] mReadHistoryUids;
     int mReadHistoryChars;
@@ -227,6 +227,38 @@
     HistoryItem mHistoryLastEnd;
     HistoryItem mHistoryCache;
 
+    // Used by computeHistoryStepDetails
+    HistoryStepDetails mLastHistoryStepDetails = null;
+    byte mLastHistoryStepLevel = 0;
+    final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails();
+    /**
+     * Total time (in 1/100 sec) spent executing in user code.
+     */
+    long mLastStepCpuUserTime;
+    long mCurStepCpuUserTime;
+    /**
+     * Total time (in 1/100 sec) spent executing in kernel code.
+     */
+    long mLastStepCpuSystemTime;
+    long mCurStepCpuSystemTime;
+    /**
+     * Times from /proc/stat
+     */
+    long mLastStepStatUserTime;
+    long mLastStepStatSystemTime;
+    long mLastStepStatIOWaitTime;
+    long mLastStepStatIrqTime;
+    long mLastStepStatSoftIrqTime;
+    long mLastStepStatIdleTime;
+    long mCurStepStatUserTime;
+    long mCurStepStatSystemTime;
+    long mCurStepStatIOWaitTime;
+    long mCurStepStatIrqTime;
+    long mCurStepStatSoftIrqTime;
+    long mCurStepStatIdleTime;
+
     private HistoryItem mHistoryIterator;
     private boolean mReadOverflow;
     private boolean mIteratingHistory;
@@ -1938,6 +1970,10 @@
     static final int STATE_BATTERY_PLUG_MASK    = 0x00000003;
     static final int STATE_BATTERY_PLUG_SHIFT   = 24;
 
+    // We use the low bit of the battery state int to indicate that we have full details
+    // from a battery level change.
+    static final int BATTERY_DELTA_LEVEL_FLAG   = 0x00000001;
+
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
@@ -1958,7 +1994,11 @@
             deltaTimeToken = (int)deltaTime;
         }
         int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
-        final int batteryLevelInt = buildBatteryLevelInt(cur);
+        final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel
+                ? BATTERY_DELTA_LEVEL_FLAG : 0;
+        final boolean computeStepDetails = includeStepDetails != 0
+                || mLastHistoryStepDetails == null;
+        final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails;
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
             firstToken |= DELTA_BATTERY_LEVEL_FLAG;
@@ -2040,12 +2080,26 @@
                     + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
                     + cur.eventTag.string);
         }
+        if (computeStepDetails) {
+            computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
+            if (includeStepDetails != 0) {
+                mCurHistoryStepDetails.writeToParcel(dest);
+            }
+            cur.stepDetails = mCurHistoryStepDetails;
+            mLastHistoryStepDetails = mCurHistoryStepDetails;
+        } else {
+            cur.stepDetails = null;
+        }
+        if (mLastHistoryStepLevel < cur.batteryLevel) {
+            mLastHistoryStepDetails = null;
+        }
+        mLastHistoryStepLevel = cur.batteryLevel;
     }
 
     private int buildBatteryLevelInt(HistoryItem h) {
         return ((((int)h.batteryLevel)<<25)&0xfe000000)
-                | ((((int)h.batteryTemperature)<<14)&0x01ffc000)
-                | (((int)h.batteryVoltage)&0x00003fff);
+                | ((((int)h.batteryTemperature)<<14)&0x01ff8000)
+                | ((((int)h.batteryVoltage)<<1)&0x00007fff);
     }
 
     private int buildStateInt(HistoryItem h) {
@@ -2063,6 +2117,98 @@
                 | (h.states&(~DELTA_STATE_MASK));
     }
 
+    private void computeHistoryStepDetails(final HistoryStepDetails out,
+            final HistoryStepDetails last) {
+        final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out;
+
+        // Perform a CPU update right after we do this collection, so we have started
+        // collecting good data for the next step.
+        requestImmediateCpuUpdate();
+
+        if (last == null) {
+            // We are not generating a delta, so all we need to do is reset the stats
+            // we will later be doing a delta from.
+            final int NU = mUidStats.size();
+            for (int i=0; i<NU; i++) {
+                final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+                uid.mLastStepUserTime = uid.mCurStepUserTime;
+                uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            }
+            mLastStepCpuUserTime = mCurStepCpuUserTime;
+            mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+            mLastStepStatUserTime = mCurStepStatUserTime;
+            mLastStepStatSystemTime = mCurStepStatSystemTime;
+            mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+            mLastStepStatIrqTime = mCurStepStatIrqTime;
+            mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+            mLastStepStatIdleTime = mCurStepStatIdleTime;
+            tmp.clear();
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTime + " sys="
+                    + mLastStepStatSystemTime + " io=" + mLastStepStatIOWaitTime
+                    + " irq=" + mLastStepStatIrqTime + " sirq="
+                    + mLastStepStatSoftIrqTime + " idle=" + mLastStepStatIdleTime);
+            Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTime + " sys="
+                    + mCurStepStatSystemTime + " io=" + mCurStepStatIOWaitTime
+                    + " irq=" + mCurStepStatIrqTime + " sirq="
+                    + mCurStepStatSoftIrqTime + " idle=" + mCurStepStatIdleTime);
+        }
+        out.userTime = (int)(mCurStepCpuUserTime - mLastStepCpuUserTime);
+        out.systemTime = (int)(mCurStepCpuSystemTime - mLastStepCpuSystemTime);
+        out.statUserTime = (int)(mCurStepStatUserTime - mLastStepStatUserTime);
+        out.statSystemTime = (int)(mCurStepStatSystemTime - mLastStepStatSystemTime);
+        out.statIOWaitTime = (int)(mCurStepStatIOWaitTime - mLastStepStatIOWaitTime);
+        out.statIrqTime = (int)(mCurStepStatIrqTime - mLastStepStatIrqTime);
+        out.statSoftIrqTime = (int)(mCurStepStatSoftIrqTime - mLastStepStatSoftIrqTime);
+        out.statIdlTime = (int)(mCurStepStatIdleTime - mLastStepStatIdleTime);
+        out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1;
+        out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0;
+        out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0;
+        final int NU = mUidStats.size();
+        for (int i=0; i<NU; i++) {
+            final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+            final int totalUTime = (int)(uid.mCurStepUserTime - uid.mLastStepUserTime);
+            final int totalSTime = (int)(uid.mCurStepSystemTime - uid.mLastStepSystemTime);
+            final int totalTime = totalUTime + totalSTime;
+            uid.mLastStepUserTime = uid.mCurStepUserTime;
+            uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            if (totalTime <= (out.appCpuUTime3+out.appCpuSTime3)) {
+                continue;
+            }
+            if (totalTime <= (out.appCpuUTime2+out.appCpuSTime2)) {
+                out.appCpuUid3 = uid.mUid;
+                out.appCpuUTime3 = totalUTime;
+                out.appCpuSTime3 = totalSTime;
+            } else {
+                out.appCpuUid3 = out.appCpuUid2;
+                out.appCpuUTime3 = out.appCpuUTime2;
+                out.appCpuSTime3 = out.appCpuSTime2;
+                if (totalTime <= (out.appCpuUTime1+out.appCpuSTime1)) {
+                    out.appCpuUid2 = uid.mUid;
+                    out.appCpuUTime2 = totalUTime;
+                    out.appCpuSTime2 = totalSTime;
+                } else {
+                    out.appCpuUid2 = out.appCpuUid1;
+                    out.appCpuUTime2 = out.appCpuUTime1;
+                    out.appCpuSTime2 = out.appCpuSTime1;
+                    out.appCpuUid1 = uid.mUid;
+                    out.appCpuUTime1 = totalUTime;
+                    out.appCpuSTime1 = totalSTime;
+                }
+            }
+        }
+        mLastStepCpuUserTime = mCurStepCpuUserTime;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+        mLastStepStatUserTime = mCurStepStatUserTime;
+        mLastStepStatSystemTime = mCurStepStatSystemTime;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+        mLastStepStatIrqTime = mCurStepStatIrqTime;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+        mLastStepStatIdleTime = mCurStepStatIdleTime;
+    }
+
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
@@ -2091,8 +2237,9 @@
             cur.numReadInts += 2;
         }
 
+        final int batteryLevelInt;
         if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
-            int batteryLevelInt = src.readInt();
+            batteryLevelInt = src.readInt();
             cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
             cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
             cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
@@ -2102,6 +2249,8 @@
                     + " batteryLevel=" + cur.batteryLevel
                     + " batteryTemp=" + cur.batteryTemperature
                     + " batteryVolt=" + (int)cur.batteryVoltage);
+        } else {
+            batteryLevelInt = 0;
         }
 
         if ((firstToken&DELTA_STATE_FLAG) != 0) {
@@ -2180,6 +2329,13 @@
         } else {
             cur.eventCode = HistoryItem.EVENT_NONE;
         }
+
+        if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
+            cur.stepDetails = mReadHistoryStepDetails;
+            cur.stepDetails.readFromParcel(src);
+        } else {
+            cur.stepDetails = null;
+        }
     }
 
     @Override
@@ -2207,6 +2363,7 @@
                 && (diffStates2&lastDiffStates2) == 0
                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
+                && mHistoryLastWritten.stepDetails == null
                 && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
                         || cur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == cur.batteryLevel
@@ -2632,6 +2789,11 @@
         }
     }
 
+    private void requestImmediateCpuUpdate() {
+        mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+        mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+    }
+
     public void setRecordAllHistoryLocked(boolean enabled) {
         mRecordAllHistory = enabled;
         if (!enabled) {
@@ -2823,6 +2985,10 @@
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
+        if (!mOnBatteryInternal) {
+            return -1;
+        }
+
         final int N = mPartialTimers.size();
         if (N == 0) {
             mLastPartialTimers.clear();
@@ -2853,7 +3019,23 @@
         return 0;
     }
 
-    public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
+    public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime,
+            int totalUTime, int totalSTime, int statUserTime, int statSystemTime,
+            int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime,
+            long[] cpuSpeedTimes) {
+        if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
+                + " user=" + statUserTime + " sys=" + statSystemTime
+                + " io=" + statIOWaitTime + " irq=" + statIrqTime
+                + " sirq=" + statSoftIrqTime + " idle=" + statIdleTime);
+        mCurStepCpuUserTime += totalUTime;
+        mCurStepCpuSystemTime += totalSTime;
+        mCurStepStatUserTime += statUserTime;
+        mCurStepStatSystemTime += statSystemTime;
+        mCurStepStatIOWaitTime += statIOWaitTime;
+        mCurStepStatIrqTime += statIrqTime;
+        mCurStepStatSoftIrqTime += statSoftIrqTime;
+        mCurStepStatIdleTime += statIdleTime;
+
         final int N = mPartialTimers.size();
         if (perc != 0) {
             int num = 0;
@@ -2874,26 +3056,24 @@
                     if (st.mInList) {
                         Uid uid = st.mUid;
                         if (uid != null && uid.mUid != Process.SYSTEM_UID) {
-                            int myUTime = utime/num;
-                            int mySTime = stime/num;
-                            utime -= myUTime;
-                            stime -= mySTime;
+                            int myUTime = remainUTime/num;
+                            int mySTime = remainSTtime/num;
+                            remainUTime -= myUTime;
+                            remainSTtime -= mySTime;
                             num--;
                             Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
-                            proc.addCpuTimeLocked(myUTime, mySTime);
-                            proc.addSpeedStepTimes(cpuSpeedTimes);
+                            proc.addCpuTimeLocked(myUTime, mySTime, cpuSpeedTimes);
                         }
                     }
                 }
             }
 
             // Just in case, collect any lost CPU time.
-            if (utime != 0 || stime != 0) {
+            if (remainUTime != 0 || remainSTtime != 0) {
                 Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
                 if (uid != null) {
                     Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
-                    proc.addCpuTimeLocked(utime, stime);
-                    proc.addSpeedStepTimes(cpuSpeedTimes);
+                    proc.addCpuTimeLocked(remainUTime, remainSTtime, cpuSpeedTimes);
                 }
             }
         }
@@ -4214,6 +4394,14 @@
         LongSamplingCounter mMobileRadioActiveCount;
 
         /**
+         * The CPU times we had at the last history details update.
+         */
+        long mLastStepUserTime;
+        long mLastStepSystemTime;
+        long mCurStepUserTime;
+        long mCurStepSystemTime;
+
+        /**
          * The statistics we have collected for this uid's wake locks.
          */
         final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
@@ -4876,6 +5064,9 @@
                 mPackageStats.clear();
             }
 
+            mLastStepUserTime = mLastStepSystemTime = 0;
+            mCurStepUserTime = mCurStepSystemTime = 0;
+
             if (!active) {
                 if (mWifiRunningTimer != null) {
                     mWifiRunningTimer.detach();
@@ -5678,9 +5869,22 @@
                 return BatteryStatsImpl.this;
             }
 
-            public void addCpuTimeLocked(int utime, int stime) {
+            public void addCpuTimeLocked(int utime, int stime, long[] speedStepBins) {
                 mUserTime += utime;
+                mCurStepUserTime += utime;
                 mSystemTime += stime;
+                mCurStepSystemTime += stime;
+
+                for (int i = 0; i < mSpeedBins.length && i < speedStepBins.length; i++) {
+                    long amt = speedStepBins[i];
+                    if (amt != 0) {
+                        SamplingCounter c = mSpeedBins[i];
+                        if (c == null) {
+                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
+                        }
+                        c.addCountAtomic(speedStepBins[i]);
+                    }
+                }
             }
 
             public void addForegroundTimeLocked(long ttime) {
@@ -5770,20 +5974,6 @@
                 return val;
             }
 
-            /* Called by ActivityManagerService when CPU times are updated. */
-            public void addSpeedStepTimes(long[] values) {
-                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
-                    long amt = values[i];
-                    if (amt != 0) {
-                        SamplingCounter c = mSpeedBins[i];
-                        if (c == null) {
-                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
-                        }
-                        c.addCountAtomic(values[i]);
-                    }
-                }
-            }
-
             @Override
             public long getTimeAtCpuSpeedStep(int speedStep, int which) {
                 if (speedStep < mSpeedBins.length) {
@@ -6756,6 +6946,18 @@
             mWakeupReasonStats.clear();
         }
 
+        mLastHistoryStepDetails = null;
+        mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
+        mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
+        mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
+        mLastStepStatUserTime = mCurStepStatUserTime = 0;
+        mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
+        mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
+        mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
+
         initDischarge();
 
         clearHistoryLocked();
@@ -6872,7 +7074,7 @@
                 reset = true;
                 mNumDischargeStepDurations = 0;
             }
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = true;
             mLastDischargeStepLevel = level;
             mMinDischargeStepLevel = level;
             mLastDischargeStepTime = -1;
@@ -6900,7 +7102,7 @@
             mDischargeAmountScreenOff = 0;
             updateTimeBasesLocked(true, !screenOn, uptime, realtime);
         } else {
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = false;
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index b5338df..501e0ec 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -152,6 +152,7 @@
     private int mRelIrqTime;
     private int mRelSoftIrqTime;
     private int mRelIdleTime;
+    private boolean mRelStatsAreGood;
 
     private int[] mCurPids;
     private int[] mCurThreadPids;
@@ -285,10 +286,9 @@
 
     public void update() {
         if (DEBUG) Slog.v(TAG, "Update: " + this);
-        mLastSampleTime = mCurrentSampleTime;
-        mCurrentSampleTime = SystemClock.uptimeMillis();
-        mLastSampleRealTime = mCurrentSampleRealTime;
-        mCurrentSampleRealTime = SystemClock.elapsedRealtime();
+
+        final long nowUptime = SystemClock.uptimeMillis();
+        final long nowRealtime = SystemClock.elapsedRealtime();
 
         final long[] sysCpu = mSystemCpuData;
         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
@@ -304,30 +304,53 @@
             final long irqtime = sysCpu[5];
             final long softirqtime = sysCpu[6];
 
-            mRelUserTime = (int)(usertime - mBaseUserTime);
-            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
-            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
-            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
-            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
-            mRelIdleTime = (int)(idletime - mBaseIdleTime);
+            // This code is trying to avoid issues with idle time going backwards,
+            // but currently it gets into situations where it triggers most of the time. :(
+            if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime
+                    && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime
+                    && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) {
+                mRelUserTime = (int)(usertime - mBaseUserTime);
+                mRelSystemTime = (int)(systemtime - mBaseSystemTime);
+                mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
+                mRelIrqTime = (int)(irqtime - mBaseIrqTime);
+                mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
+                mRelIdleTime = (int)(idletime - mBaseIdleTime);
+                mRelStatsAreGood = true;
 
-            if (DEBUG) {
-                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
-                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
-                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
-                      + " O:" + sysCpu[6]);
-                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
-                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                if (DEBUG) {
+                    Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
+                          + " S:" + sysCpu[2] + " I:" + sysCpu[3]
+                          + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
+                          + " O:" + sysCpu[6]);
+                    Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
+                          + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                }
+
+                mBaseUserTime = usertime;
+                mBaseSystemTime = systemtime;
+                mBaseIoWaitTime = iowaittime;
+                mBaseIrqTime = irqtime;
+                mBaseSoftIrqTime = softirqtime;
+                mBaseIdleTime = idletime;
+
+            } else {
+                mRelUserTime = 0;
+                mRelSystemTime = 0;
+                mRelIoWaitTime = 0;
+                mRelIrqTime = 0;
+                mRelSoftIrqTime = 0;
+                mRelIdleTime = 0;
+                mRelStatsAreGood = false;
+                Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
+                return;
             }
-
-            mBaseUserTime = usertime;
-            mBaseSystemTime = systemtime;
-            mBaseIoWaitTime = iowaittime;
-            mBaseIrqTime = irqtime;
-            mBaseSoftIrqTime = softirqtime;
-            mBaseIdleTime = idletime;
         }
 
+        mLastSampleTime = mCurrentSampleTime;
+        mCurrentSampleTime = nowUptime;
+        mLastSampleRealTime = mCurrentSampleRealTime;
+        mCurrentSampleRealTime = nowRealtime;
+
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
             mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
@@ -647,6 +670,10 @@
         return mRelIdleTime;
     }
 
+    final public boolean hasGoodLastStats() {
+        return mRelStatsAreGood;
+    }
+
     final public float getTotalCpuPercent() {
         int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
         if (denom <= 0) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index c9b44be..a55fe9a 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -399,7 +399,7 @@
                 throws IllegalArgumentException {
             int curArg = 0;
 
-            boolean seenRuntimeArgs = true;
+            boolean seenRuntimeArgs = false;
 
             for ( /* curArg */ ; curArg < args.length; curArg++) {
                 String arg = args[curArg];
@@ -533,14 +533,18 @@
                 }
             }
 
-            if (!seenRuntimeArgs) {
-                throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+            if (abiListQuery) {
+                if (args.length - curArg > 0) {
+                    throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
+                }
+            } else {
+                if (!seenRuntimeArgs) {
+                    throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+                }
+
+                remainingArgs = new String[args.length - curArg];
+                System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
             }
-
-            remainingArgs = new String[args.length - curArg];
-
-            System.arraycopy(args, curArg, remainingArgs, 0,
-                    remainingArgs.length);
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 035b017..400ea37 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -504,8 +504,8 @@
             "--setgid=1000",
             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
             "--capabilities=" + capabilities + "," + capabilities,
-            "--runtime-init",
             "--nice-name=system_server",
+            "--runtime-args",
             "com.android.server.SystemServer",
         };
         ZygoteConnection.Arguments parsedArgs = null;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index a3c0db4..2b0d244 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -1,19 +1,19 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.statusbar;
 
 import com.android.internal.statusbar.StatusBarIcon;
@@ -43,5 +43,26 @@
     void preloadRecentApps();
     void cancelPreloadRecentApps();
     void showScreenPinningRequest();
+
+    /**
+     * Notifies the status bar that an app transition is pending to delay applying some flags with
+     * visual impact until {@link #appTransitionReady} is called.
+     */
+    void appTransitionPending();
+
+    /**
+     * Notifies the status bar that a pending app transition has been cancelled.
+     */
+    void appTransitionCancelled();
+
+    /**
+     * Notifies the status bar that an app transition is now being executed.
+     *
+     * @param statusBarAnimationsStartTime the desired start time for all visual animations in the
+     *        status bar caused by this app transition in uptime millis
+     * @param statusBarAnimationsDuration the duration for all visual animations in the status
+     *        bar caused by this app transition in millis
+     */
+    void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
 }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 40c009f..6cb839e 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -1,16 +1,16 @@
 /**
  * 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 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0 
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
- * Unless required by applicable law or agreed to in writing, software 
- * distributed under the License is distributed on an "AS IS" BASIS, 
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
- * See the License for the specific language governing permissions and 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
@@ -61,4 +61,25 @@
     void toggleRecentApps();
     void preloadRecentApps();
     void cancelPreloadRecentApps();
+
+    /**
+     * Notifies the status bar that an app transition is pending to delay applying some flags with
+     * visual impact until {@link #appTransitionReady} is called.
+     */
+    void appTransitionPending();
+
+    /**
+     * Notifies the status bar that a pending app transition has been cancelled.
+     */
+    void appTransitionCancelled();
+
+    /**
+     * Notifies the status bar that an app transition is now being executed.
+     *
+     * @param statusBarAnimationsStartTime the desired start time for all visual animations in the
+     *        status bar caused by this app transition in uptime millis
+     * @param statusBarAnimationsDuration the duration for all visual animations in the status
+     *        bar caused by this app transition in millis
+     */
+    void appTransitionStarting(long statusBarAnimationsStartTime, long statusBarAnimationsDuration);
 }
diff --git a/core/java/com/android/internal/view/ActionModeWrapper.java b/core/java/com/android/internal/view/ActionModeWrapper.java
new file mode 100644
index 0000000..72066b9
--- /dev/null
+++ b/core/java/com/android/internal/view/ActionModeWrapper.java
@@ -0,0 +1,205 @@
+/*
+ * 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.view;
+
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.internal.view.menu.MenuBuilder;
+
+/**
+ * ActionMode implementation that wraps several actions modes and creates them on the fly depending
+ * on the ActionMode type chosen by the client.
+ */
+public class ActionModeWrapper extends ActionMode {
+
+    /**
+     * Interface to defer the ActionMode creation until the type is chosen.
+     */
+    public interface ActionModeProvider {
+        /**
+         * Create the desired ActionMode, that will immediately be used as the current active mode
+         * in the decorator.
+         *
+         * @param callback The {@link ActionMode.Callback} to be used.
+         * @param menuBuilder The {@link MenuBuilder} that should be used by the created
+         *      {@link ActionMode}. This will already have been populated.
+         * @return A new {@link ActionMode} ready to be used that uses menuBuilder as its menu.
+         */
+        ActionMode createActionMode(ActionMode.Callback callback, MenuBuilder menuBuilder);
+    }
+
+    private ActionMode mActionMode;
+    private final Context mContext;
+    private MenuBuilder mMenu;
+    private final ActionMode.Callback mCallback;
+    private boolean mTypeLocked = false;
+
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+    private View mCustomView;
+    
+    private final ActionModeProvider mActionModeProvider;
+
+    public ActionModeWrapper(
+            Context context, ActionMode.Callback callback, ActionModeProvider actionModeProvider) {
+        mContext = context;
+        mMenu = new MenuBuilder(context).setDefaultShowAsAction(
+                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mCallback = callback;
+        mActionModeProvider = actionModeProvider;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(title);
+        } else {
+            mTitle = title;
+        }
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(resId);
+        } else {
+            mTitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(subtitle);
+        } else {
+            mSubtitle = subtitle;
+        }
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(resId);
+        } else {
+            mSubtitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        if (mActionMode != null) {
+            mActionMode.setCustomView(view);
+        } else {
+            mCustomView = view;
+        }
+    }
+
+    /**
+     * Set the current type as final and create the necessary ActionMode. After this call, any
+     * changes to the ActionMode type will be ignored.
+     */
+    public void lockType() {
+        mTypeLocked = true;
+        switch (getType()) {
+            case ActionMode.TYPE_PRIMARY:
+            default:
+                mActionMode = mActionModeProvider.createActionMode(mCallback, mMenu);
+                break;
+            case ActionMode.TYPE_FLOATING:
+                // Not implemented yet.
+                break;
+        }
+
+        if (mActionMode == null) {
+            return;
+        }
+
+        mActionMode.setTitle(mTitle);
+        mActionMode.setSubtitle(mSubtitle);
+        if (mCustomView != null) {
+            mActionMode.setCustomView(mCustomView);
+        }
+
+        mTitle = null;
+        mSubtitle = null;
+        mCustomView = null;
+    }
+
+    @Override
+    public void setType(int type) {
+        if (!mTypeLocked) {
+            super.setType(type);
+        } else {
+            throw new IllegalStateException(
+                    "You can't change the ActionMode's type after onCreateActionMode.");
+        }
+    }
+
+    @Override
+    public void invalidate() {
+        if (mActionMode != null) {
+            mActionMode.invalidate();
+        }
+    }
+
+    @Override
+    public void finish() {
+        if (mActionMode != null) {
+            mActionMode.finish();
+        }
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        if (mActionMode != null) {
+            return mActionMode.getTitle();
+        }
+        return mTitle;
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        if (mActionMode != null) {
+            return mActionMode.getSubtitle();
+        }
+        return mSubtitle;
+    }
+
+    @Override
+    public View getCustomView() {
+        if (mActionMode != null) {
+            return mActionMode.getCustomView();
+        }
+        return mCustomView;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return new MenuInflater(mContext);
+    }
+
+}
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index d5d3602..2812b77 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -20,6 +20,7 @@
 import com.android.internal.view.menu.SubMenuBuilder;
 import com.android.internal.widget.ActionBarContextView;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.view.ActionMode;
 import android.view.Menu;
@@ -41,13 +42,15 @@
     private MenuBuilder mMenu;
 
     public StandaloneActionMode(Context context, ActionBarContextView view,
-            ActionMode.Callback callback, boolean isFocusable) {
+            ActionMode.Callback callback, boolean isFocusable, @Nullable MenuBuilder menuBuilder) {
         mContext = context;
         mContextView = view;
         mCallback = callback;
 
-        mMenu = new MenuBuilder(view.getContext()).setDefaultShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mMenu = (menuBuilder != null)
+                ? menuBuilder
+                : new MenuBuilder(view.getContext()).setDefaultShowAsAction(
+                        MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mMenu.setCallback(this);
         mFocusable = isFocusable;
     }
@@ -64,12 +67,12 @@
 
     @Override
     public void setTitle(int resId) {
-        setTitle(mContext.getString(resId));
+        setTitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
     public void setSubtitle(int resId) {
-        setSubtitle(mContext.getString(resId));
+        setSubtitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 5d3f464..ae5999a 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -158,7 +158,7 @@
             removeView(mCustomView);
         }
         mCustomView = view;
-        if (mTitleLayout != null) {
+        if (view != null && mTitleLayout != null) {
             removeView(mTitleLayout);
             mTitleLayout = null;
         }
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index f539127..9e49afb 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -82,7 +82,7 @@
 static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
         jlong layerUpdaterPtr) {
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return layer->backingLayer()->getTexture();
+    return layer->backingLayer()->getTextureId();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 7f6c50f..bfa0534 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -49,6 +49,7 @@
 
 #include <AnimationContext.h>
 #include <DisplayListRenderer.h>
+#include <FrameInfo.h>
 #include <RenderNode.h>
 #include <renderthread/RenderProxy.h>
 
@@ -394,7 +395,7 @@
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
     // to all 0s. (and width & height are unused, TODO remove them)
-    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0);
+    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0, 1.0f);
     return (jlong) proxy;
 }
 
@@ -406,8 +407,11 @@
 
 static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-    proxy->syncAndDrawFrame(frameTimeNs, 0, 1.0f);
+    nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
+    UiFrameInfoBuilder(proxy->frameInfo())
+            .setVsync(vsync, vsync)
+            .addFlag(FrameInfoFlags::kSurfaceCanvas);
+    proxy->syncAndDrawFrame();
 }
 
 static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 068b24e..ad93301 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -281,10 +281,10 @@
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
         jint width, jint height,
         jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius,
-        jint ambientShadowAlpha, jint spotShadowAlpha) {
+        jint ambientShadowAlpha, jint spotShadowAlpha, jfloat density) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
-            ambientShadowAlpha, spotShadowAlpha);
+            ambientShadowAlpha, spotShadowAlpha, density);
 }
 
 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -294,9 +294,13 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
+        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
+            "Mismatched size expectations, given %d expected %d",
+            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
+    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
+    return proxy->syncAndDrawFrame();
 }
 
 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -391,10 +395,10 @@
 }
 
 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jobject javaFileDescriptor) {
+        jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    proxy->dumpProfileInfo(fd);
+    proxy->dumpProfileInfo(fd, dumpFlags);
 }
 
 // ----------------------------------------------------------------------------
@@ -425,9 +429,9 @@
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
-    { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetup", "(JIIFFFFIIF)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
-    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
@@ -442,7 +446,7 @@
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
     { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
-    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
+    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
 };
diff --git a/core/res/res/color/white_disabled_material.xml b/core/res/res/color/white_disabled_material.xml
new file mode 100644
index 0000000..c61f900
--- /dev/null
+++ b/core/res/res/color/white_disabled_material.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="@color/white"
+          android:alpha="?attr/disabledAlpha" />
+</selector>
diff --git a/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index fbb2e0c..0000000
--- a/core/res/res/drawable-hdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index 92d4b05..0000000
--- a/core/res/res/drawable-mdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index e3c4eeb..0000000
--- a/core/res/res/drawable-xhdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png b/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
deleted file mode 100644
index 452f45c..0000000
--- a/core/res/res/drawable-xxhdpi/progress_mtrl_alpha.9.png
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml
index 6b64337..c179564 100644
--- a/core/res/res/drawable/progress_horizontal_material.xml
+++ b/core/res/res/drawable/progress_horizontal_material.xml
@@ -15,22 +15,32 @@
 -->
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:id="@id/background">
-        <nine-patch android:src="@drawable/progress_mtrl_alpha"
-            android:tint="?attr/colorControlNormal"
-            android:alpha="?attr/disabledAlpha" />
+    <item android:id="@id/background"
+          android:gravity="center_vertical|fill_horizontal">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlNormal">
+            <size android:height="@dimen/progress_bar_height_material" />
+            <solid android:color="@color/white_disabled_material" />
+        </shape>
     </item>
-    <item android:id="@id/secondaryProgress">
+    <item android:id="@id/secondaryProgress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
-            <nine-patch android:src="@drawable/progress_mtrl_alpha"
-                android:tint="?attr/colorControlActivated"
-                android:alpha="?attr/disabledAlpha" />
+            <shape android:shape="rectangle"
+                   android:tint="?attr/colorControlActivated">
+                <size android:height="@dimen/progress_bar_height_material" />
+                <solid android:color="@color/white_disabled_material" />
+            </shape>
         </scale>
     </item>
-    <item android:id="@id/progress">
+    <item android:id="@id/progress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
-            <nine-patch android:src="@drawable/progress_mtrl_alpha"
-                android:tint="?attr/colorControlActivated" />
+            <shape android:shape="rectangle"
+                   android:tint="?attr/colorControlActivated">
+                <size android:height="@dimen/progress_bar_height_material" />
+                <solid android:color="@color/white" />
+            </shape>
         </scale>
     </item>
 </layer-list>
diff --git a/core/res/res/drawable/scrubber_progress_horizontal_material.xml b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
index 89a1787..86a85c3 100644
--- a/core/res/res/drawable/scrubber_progress_horizontal_material.xml
+++ b/core/res/res/drawable/scrubber_progress_horizontal_material.xml
@@ -15,32 +15,42 @@
 -->
 
 <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 android:id="@id/background"
+          android:gravity="center_vertical|fill_horizontal">
+        <shape android:shape="rectangle"
+               android:tint="?attr/colorControlNormal">
+            <size android:height="@dimen/scrubber_track_height_material" />
+            <solid android:color="@color/white_disabled_material" />
+        </shape>
     </item>
-    <item android:id="@id/secondaryProgress">
+    <item android:id="@id/secondaryProgress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
             <selector>
-                <item android:state_enabled="false">
-                    <color android:color="@color/transparent" />
-                </item>
+                <item android:state_enabled="false"
+                      android:drawable="@color/transparent" />
                 <item>
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                                android:tint="?attr/colorControlNormal" />
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorControlActivated">
+                        <size android:height="@dimen/scrubber_track_height_material" />
+                        <solid android:color="@color/white_disabled_material" />
+                    </shape>
                 </item>
             </selector>
         </scale>
     </item>
-    <item android:id="@id/progress">
+    <item android:id="@id/progress"
+          android:gravity="center_vertical|fill_horizontal">
         <scale android:scaleWidth="100%">
             <selector>
-                <item android:state_enabled="false">
-                    <color android:color="@color/transparent" />
-                </item>
+                <item android:state_enabled="false"
+                      android:drawable="@color/transparent" />
                 <item>
-                    <nine-patch android:src="@drawable/scrubber_primary_mtrl_alpha"
-                                android:tint="?attr/colorControlActivated" />
+                    <shape android:shape="rectangle"
+                           android:tint="?attr/colorControlActivated">
+                        <size android:height="@dimen/progress_bar_height_material" />
+                        <solid android:color="@color/white" />
+                    </shape>
                 </item>
             </selector>
         </scale>
diff --git a/core/res/res/drawable/switch_track_material.xml b/core/res/res/drawable/switch_track_material.xml
index a825fe4..8b028d3 100644
--- a/core/res/res/drawable/switch_track_material.xml
+++ b/core/res/res/drawable/switch_track_material.xml
@@ -16,12 +16,12 @@
 
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:gravity="center_vertical|fill_horizontal"
-          android:start="2dp"
-          android:end="2dp">
+          android:start="4dp"
+          android:end="4dp">
         <shape android:shape="rectangle"
                android:tint="@color/switch_track_material">
             <corners android:radius="7dp" />
-            <solid android:color="#4dffffff" />
+            <solid android:color="@color/white_disabled_material" />
             <size android:height="14dp" />
         </shape>
     </item>
diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml
index 6ccde33..46e7c54 100644
--- a/core/res/res/layout/time_header_label.xml
+++ b/core/res/res/layout/time_header_label.xml
@@ -14,69 +14,71 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/time_header"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:padding="@dimen/timepicker_separator_padding"
-    android:gravity="center">
+    android:gravity="center"
+    android:orientation="horizontal"
+    android:padding="@dimen/timepicker_separator_padding">
 
-    <LinearLayout
+    <!-- The hour should always be to the left of the separator,
+         regardless of the current locale's layout direction. -->
+    <TextView
+        android:id="@+id/hours"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"
-        android:gravity="bottom"
-        android:orientation="horizontal"
-        android:layoutDirection="ltr">
+        android:layout_toLeftOf="@+id/separator"
+        android:layout_alignBaseline="@+id/separator"
+        android:gravity="right" />
 
-        <TextView
-            android:id="@+id/hours"
+    <TextView
+        android:id="@+id/separator"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginLeft="@dimen/timepicker_separator_padding"
+        android:layout_marginRight="@dimen/timepicker_separator_padding"
+        android:layout_centerInParent="true"
+        android:importantForAccessibility="no" />
+
+    <!-- The minutes should always be to the left of the separator,
+         regardless of the current locale's layout direction. -->
+    <TextView
+        android:id="@+id/minutes"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@+id/separator"
+        android:layout_alignBaseline="@+id/separator"
+        android:gravity="left" />
+
+    <!-- The layout alignment of this view will switch between toRightOf
+         @id/minutes and toLeftOf @id/hours depending on the locale. -->
+    <LinearLayout
+        android:id="@+id/ampm_layout"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_toRightOf="@+id/minutes"
+        android:layout_alignBaseline="@+id/minutes"
+        android:orientation="vertical"
+        android:baselineAlignedChildIndex="1">
+        <CheckedTextView
+            android:id="@+id/am_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:gravity="right"
-            android:layoutDirection="locale" />
-
-        <TextView
-            android:id="@+id/separator"
+            android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingTop="@dimen/timepicker_ampm_vertical_padding"
+            android:lines="1"
+            android:ellipsize="none" />
+        <CheckedTextView
+            android:id="@+id/pm_label"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="@dimen/timepicker_separator_padding"
-            android:layout_marginRight="@dimen/timepicker_separator_padding"
-            android:importantForAccessibility="no"
-            android:layoutDirection="locale" />
-
-        <TextView
-            android:id="@+id/minutes"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:gravity="left"
-            android:layoutDirection="locale" />
-
-        <LinearLayout
-            android:id="@+id/ampm_layout"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:baselineAlignedChildIndex="1"
-            android:layoutDirection="locale">
-            <CheckedTextView
-                android:id="@+id/am_label"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingTop="@dimen/timepicker_ampm_vertical_padding"
-                android:lines="1"
-                android:ellipsize="none" />
-            <CheckedTextView
-                android:id="@+id/pm_label"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
-                android:paddingTop="@dimen/timepicker_pm_top_padding"
-                android:lines="1"
-                android:ellipsize="none" />
-        </LinearLayout>
+            android:paddingStart="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding"
+            android:paddingTop="@dimen/timepicker_pm_top_padding"
+            android:lines="1"
+            android:ellipsize="none" />
     </LinearLayout>
-</FrameLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/time_picker_holo.xml b/core/res/res/layout/time_picker_holo.xml
index 7a9f90a..cb25dbe 100644
--- a/core/res/res/layout/time_picker_holo.xml
+++ b/core/res/res/layout/time_picker_holo.xml
@@ -28,7 +28,7 @@
         android:layout_gravity="center" />
     <android.widget.RadialTimePickerView
         android:id="@+id/radial_picker"
-        android:layout_width="@dimen/timepicker_radial_picker_dimen"
+        android:layout_width="wrap_content"
         android:layout_height="@dimen/timepicker_radial_picker_dimen"
         android:layout_gravity="center"
         android:layout_marginTop="?attr/dialogPreferredPadding"
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index cf2f808..1db68ce 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -1058,7 +1058,7 @@
     <string name="factorytest_reboot" msgid="6320168203050791643">"Վերաբեռնել"</string>
     <string name="js_dialog_title" msgid="1987483977834603872">"«<xliff:g id="TITLE">%s</xliff:g>»-ի էջում ասվում է`"</string>
     <string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
-    <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Հաստատել կողմնորոշումը"</string>
+    <string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Գործողության հաստատում"</string>
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Լքել այս էջը"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Մնալ այս էջում"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nՎստա՞հ եք, որ ցանկանում եք հեռանալ այս էջից:"</string>
diff --git a/core/res/res/values-mcc259-mnc05/config.xml b/core/res/res/values-mcc259-mnc05/config.xml
new file mode 100644
index 0000000..065668c
--- /dev/null
+++ b/core/res/res/values-mcc259-mnc05/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The list of ril radio technologies (see ServiceState.java) which only support
+         a single data connection at one time.  This may change by carrier via
+         overlays (some don't support multiple pdp on UMTS).  All unlisted radio
+         tech types support unlimited types (practically only 2-4 used). -->
+    <integer-array name="config_onlySingleDcAllowed">
+        <item>1</item>  <!-- GPRS -->
+        <item>2</item>  <!-- EDGE -->
+        <item>3</item>  <!-- UMTS -->
+        <item>9</item>  <!-- HSDPA -->
+        <item>10</item> <!-- HSUPA -->
+        <item>11</item> <!-- HSPA -->
+        <item>14</item> <!-- LTE -->
+        <item>15</item> <!-- HSPAP -->
+    </integer-array>
+</resources>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 307a1ea..745aa73 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -43,4 +43,12 @@
     <!-- Flags enabling default window features. See Window.java -->
     <bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
     <bool name="config_defaultWindowFeatureContextMenu">false</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">25</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.1</item>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bc20378..6bb61a2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4778,6 +4778,8 @@
         <attr name="headerBackground" />
         <!-- The color for the hours/minutes numbers. -->
         <attr name="numbersTextColor" format="color" />
+        <!-- The color for the inner hours numbers used in 24-hour mode. -->
+        <attr name="numbersInnerTextColor" format="color" />
         <!-- The background color for the hours/minutes numbers. -->
         <attr name="numbersBackgroundColor" format="color" />
         <!-- The color for the AM/PM selectors. -->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2041777..4c0520e 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1852,6 +1852,12 @@
         <item>users</item>
     </string-array>
 
+    <!-- Number of milliseconds to hold a wake lock to ensure that drawing is fully
+         flushed to the display while dozing.  This value needs to be large enough
+         to account for processing and rendering time plus a frame or two of latency
+         in the display pipeline plus some slack just to be sure. -->
+    <integer name="config_drawLockTimeoutMillis">120</integer>
+
     <!-- default telephony hardware configuration for this platform.
     -->
     <!-- this string array should be overridden by the device to present a list
@@ -2060,4 +2066,12 @@
 
     <!-- Whether to start in touch mode -->
     <bool name="config_defaultInTouchMode">true</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">-50</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index bec224e..d240047 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -31,7 +31,7 @@
     <integer name="max_action_buttons">2</integer>
     <dimen name="toast_y_offset">64dip</dimen>
     <!-- Height of the status bar -->
-    <dimen name="status_bar_height">25dip</dimen>
+    <dimen name="status_bar_height">24dp</dimen>
     <!-- Height of the bottom navigation / system bar. -->
     <dimen name="navigation_bar_height">48dp</dimen>
     <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
@@ -357,26 +357,23 @@
     <dimen name="subtitle_outline_width">2dp</dimen>
 
     <!-- New TimePicker dimensions. -->
-    <item name="timepicker_selection_radius_multiplier" format="float" type="dimen">0.16</item>
-    <item name="timepicker_numbers_radius_multiplier_normal" format="float" type="dimen">0.81</item>
-    <item name="timepicker_numbers_radius_multiplier_inner" format="float" type="dimen">0.60</item>
-    <item name="timepicker_numbers_radius_multiplier_outer" format="float" type="dimen">0.83</item>
-    <item name="timepicker_text_size_multiplier_normal" format="float" type="dimen">0.17</item>
-    <item name="timepicker_text_size_multiplier_inner" format="float" type="dimen">0.14</item>
-    <item name="timepicker_text_size_multiplier_outer" format="float" type="dimen">0.11</item>
-    <item name="timepicker_transition_mid_radius_multiplier" format="float" type="dimen">0.95</item>
-    <item name="timepicker_transition_end_radius_multiplier" format="float" type="dimen">1.3</item>
+    <dimen name="timepicker_selector_radius">24dp</dimen>
+    <dimen name="timepicker_center_dot_radius">4dp</dimen>
+    <dimen name="timepicker_selector_dot_radius">4dp</dimen>
+    <dimen name="timepicker_text_inset_normal">26dp</dimen>
+    <dimen name="timepicker_text_inset_inner">58dp</dimen>
+    <dimen name="timepicker_text_size_normal">14sp</dimen>
+    <dimen name="timepicker_text_size_inner">12sp</dimen>
 
-    <dimen name="timepicker_time_label_size">60sp</dimen>
-    <dimen name="timepicker_extra_time_label_margin">-30dp</dimen>
+    <!-- Text size for the time picker header HH:MM label. This value is large
+         enough that we don't need to use scaled pixels, dp is fine. -->
+    <dimen name="timepicker_time_label_size">60dp</dimen>
     <dimen name="timepicker_ampm_label_size">16sp</dimen>
     <dimen name="timepicker_ampm_horizontal_padding">12dp</dimen>
     <dimen name="timepicker_ampm_vertical_padding">16dp</dimen>
     <dimen name="timepicker_pm_top_padding">3dp</dimen>
     <dimen name="timepicker_separator_padding">4dp</dimen>
     <dimen name="timepicker_header_height">96dp</dimen>
-    <dimen name="timepicker_minimum_margin_sides">48dp</dimen>
-    <dimen name="timepicker_minimum_margin_top_bottom">24dp</dimen>
     <dimen name="timepicker_radial_picker_dimen">270dp</dimen>
 
     <!-- Used by SimpleMonthView -->
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 0e2c480..b84249a 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -115,5 +115,6 @@
     <!-- Padding above and below selection dialog lists. -->
     <dimen name="dialog_list_padding_vertical_material">8dp</dimen>
 
+    <dimen name="scrubber_track_height_material">2dp</dimen>
     <dimen name="progress_bar_height_material">4dp</dimen>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bd24f3e..1f4d37c 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -89,4 +89,6 @@
   <item type="id" name="parentMatrix" />
   <item type="id" name="statusBarBackground" />
   <item type="id" name="navigationBarBackground" />
+  <item type="id" name="undo" />
+  <item type="id" name="redo" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cfff420..af8ff41 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2614,6 +2614,7 @@
   <public type="attr" name="start" />
   <public type="attr" name="end" />
   <public type="attr" name="windowHasLightStatusBar" />
+  <public type="attr" name="numbersInnerTextColor" />
 
   <public type="style" name="Widget.Material.Button.Colored" />
 
@@ -2634,4 +2635,9 @@
   <public type="style" name="Theme.Material.DayNight.Panel" />
   <public type="style" name="Theme.Material.Light.LightStatusBar" />
 
+  <!-- Context menu ID for the "Undo" menu item to undo the last text edit operation. -->
+  <public type="id" name="undo" />
+  <!-- Context menu ID for the "Redo" menu item to redo the last text edit operation. -->
+  <public type="id" name="redo" />
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index ff03ca9..d95b17e 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3909,6 +3909,8 @@
     <string name="usb_mtp_notification_title">Connected as a media device</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in PTP mode.  This is the title -->
     <string name="usb_ptp_notification_title">Connected as a camera</string>
+    <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in MIDI mode.  This is the title -->
+    <string name="usb_midi_notification_title">Connected as a MIDI device</string>
     <!-- USB_PREFERENCES: Notification for when the user connects the phone to a computer via USB in mass storage mode (for installer CD image).  This is the title -->
     <string name="usb_cd_installer_notification_title">Connected as an installer</string>
     <!-- USB_PREFERENCES: Notification for when a USB accessory is attached.  This is the title -->
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index c618707..d75e496 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -653,7 +653,8 @@
         <item name="headerAmPmTextAppearance">@style/TextAppearance.Material.TimePicker.AmPmLabel</item>
         <item name="headerSelectedTextColor">?attr/textColorPrimaryInverse</item>
         <item name="headerBackground">@drawable/time_picker_header_material</item>
-        <item name="numbersTextColor">?attr/textColorSecondaryActivated</item>
+        <item name="numbersTextColor">?attr/textColorPrimaryActivated</item>
+        <item name="numbersInnerTextColor">?attr/textColorSecondaryActivated</item>
         <item name="numbersBackgroundColor">#10ffffff</item>
         <item name="numbersSelectorColor">?attr/colorControlActivated</item>
         <item name="amPmTextColor">?attr/textColorSecondary</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c43977da..615f445 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -345,6 +345,7 @@
   <java-symbol type="integer" name="config_bluetooth_max_advertisers" />
   <java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
   <java-symbol type="integer" name="config_cursorWindowSize" />
+  <java-symbol type="integer" name="config_drawLockTimeoutMillis" />
   <java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
   <java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
   <java-symbol type="integer" name="config_extraFreeKbytesAbsolute" />
@@ -1750,6 +1751,7 @@
   <java-symbol type="string" name="usb_notification_message" />
   <java-symbol type="string" name="use_physical_keyboard" />
   <java-symbol type="string" name="usb_ptp_notification_title" />
+  <java-symbol type="string" name="usb_midi_notification_title" />
   <java-symbol type="string" name="vpn_text" />
   <java-symbol type="string" name="vpn_text_long" />
   <java-symbol type="string" name="vpn_title" />
@@ -1996,15 +1998,13 @@
   <java-symbol type="string" name="deleted_key" />
   <java-symbol type="string" name="sans_serif" />
   <java-symbol type="string" name="radial_numbers_typeface" />
-  <java-symbol type="dimen" name="timepicker_text_size_multiplier_inner" />
-  <java-symbol type="dimen" name="timepicker_text_size_multiplier_outer" />
-  <java-symbol type="dimen" name="timepicker_text_size_multiplier_normal" />
-  <java-symbol type="dimen" name="timepicker_numbers_radius_multiplier_outer" />
-  <java-symbol type="dimen" name="timepicker_selection_radius_multiplier" />
-  <java-symbol type="dimen" name="timepicker_numbers_radius_multiplier_inner" />
-  <java-symbol type="dimen" name="timepicker_numbers_radius_multiplier_normal" />
-  <java-symbol type="dimen" name="timepicker_transition_mid_radius_multiplier" />
-  <java-symbol type="dimen" name="timepicker_transition_end_radius_multiplier" />
+  <java-symbol type="dimen" name="timepicker_selector_radius" />
+  <java-symbol type="dimen" name="timepicker_selector_dot_radius" />
+  <java-symbol type="dimen" name="timepicker_center_dot_radius" />
+  <java-symbol type="dimen" name="timepicker_text_inset_normal" />
+  <java-symbol type="dimen" name="timepicker_text_inset_inner" />
+  <java-symbol type="dimen" name="timepicker_text_size_normal" />
+  <java-symbol type="dimen" name="timepicker_text_size_inner" />
   <java-symbol type="string" name="battery_saver_description" />
   <java-symbol type="string" name="downtime_condition_summary" />
   <java-symbol type="string" name="downtime_condition_line_one" />
@@ -2157,4 +2157,7 @@
   <java-symbol type="xml" name="bookmarks" />
 
   <java-symbol type="integer" name="config_defaultNightMode" />
+
+  <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
+  <java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" />
 </resources>
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
index 1557918..a50fb54 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -29,8 +29,6 @@
 import com.android.internal.inputmethod.InputMethodUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -38,19 +36,33 @@
 public class InputMethodTest extends InstrumentationTestCase {
     private static final boolean IS_AUX = true;
     private static final boolean IS_DEFAULT = true;
-    private static final boolean IS_AUTO = true;
+    private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
     private static final boolean IS_ASCII_CAPABLE = true;
+    private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
     private static final boolean IS_SYSTEM_READY = true;
-    private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
+    private static final Locale LOCALE_EN = new Locale("en");
     private static final Locale LOCALE_EN_US = new Locale("en", "US");
     private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
     private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FI = new Locale("fi");
+    private static final Locale LOCALE_FI_FI = new Locale("fi", "FI");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_FR = new Locale("fr");
+    private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
     private static final Locale LOCALE_HI = new Locale("hi");
     private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
     private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
     private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
+    private static final Locale LOCALE_IN = new Locale("in");
+    private static final Locale LOCALE_ID = new Locale("id");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
+    private static final String SUBTYPE_MODE_ANY = null;
+    private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
+    private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
+    private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
+            "EnabledWhenDefaultIsNotAsciiCapable";
 
     @SmallTest
     public void testVoiceImes() throws Exception {
@@ -159,10 +171,415 @@
         }
     }
 
+    @SmallTest
+    public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
+        // selected no matter what locale is specified.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(autoSubtype);  // overridesImplicitlyEnabledSubtype == true
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(autoSubtype, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);  // locale == "en_US"
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB); // locale == "en_GB"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_GB, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnGB, result.get(0));
+        }
+
+        // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
+        // any subtype whose locale is exactly equal to the specified locale in the given list,
+        // try to find a subtype whose language is equal to the language part of the given locale.
+        // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFrCA);  // locale == "fr_CA"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+        // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFr);  // locale == "fr"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR_CA, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+
+        // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
+        // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoJa);    // not ASCII capable
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_JA_JP, imi);
+            assertEquals(3, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
+        }
+
+        // Make sure that 3-letter language code can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FIL_PH, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFil, result.get(0));
+        }
+
+        // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
+        // Also make sure that the first subtype will be used as the last-resort candidate.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FI, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+        }
+
+        // Make sure that "in" and "id" conversion is taken into account.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+    }
+
+    @SmallTest
+    public void testContainsSubtypeOf() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        final boolean CHECK_COUNTRY = true;
+
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil_PH") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFilPH);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "in" can be queried with "id".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "id" can be queried with "in".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+    }
+
+    private ArrayList<InputMethodSubtype> callGetImplicitlyApplicableSubtypesLockedWithLocale(
+            final Locale locale, final InputMethodInfo imi) {
+        final Context context = getInstrumentation().getTargetContext();
+        final Locale initialLocale = context.getResources().getConfiguration().locale;
+        try {
+            context.getResources().getConfiguration().setLocale(locale);
+            return InputMethodUtils.getImplicitlyApplicableSubtypesLocked(context.getResources(),
+                    imi);
+        } finally {
+            context.getResources().getConfiguration().setLocale(initialLocale);
+        }
+    }
+
     private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
             final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) {
         final Context context = getInstrumentation().getTargetContext();
-        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesUnderWithLocale(
+        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesWithLocale(
                 context, isSystemReady, preinstalledImes, systemLocale));
         assertEquals(expectedImeNames.length, actualImeNames.length);
         for (int i = 0; i < expectedImeNames.length; ++i) {
@@ -184,7 +601,7 @@
         }
     }
 
-    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesUnderWithLocale(
+    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesWithLocale(
             final Context context, final boolean isSystemReady,
             final ArrayList<InputMethodInfo> imis, final Locale locale) {
         final Locale initialLocale = context.getResources().getConfiguration().locale;
@@ -210,11 +627,15 @@
         for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
             final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
             final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
-            assertEquals(expectedSubtype, actualSubtype);
-            assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
+            verifyEquality(expectedSubtype, actualSubtype);
         }
     }
 
+    private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
+        assertEquals(expected, actual);
+        assertEquals(expected.hashCode(), actual.hashCode());
+    }
+
     private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
             CharSequence label, boolean isAuxIme, boolean isDefault,
             List<InputMethodSubtype> subtypes) {
@@ -236,13 +657,27 @@
 
     private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
-            boolean isAsciiCapable) {
+            boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
+
+        final StringBuilder subtypeExtraValue = new StringBuilder();
+        if (isEnabledWhenDefaultIsNotAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        }
+
+        // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
+        // available since API level 19 (KitKat). We no longer need to rely on extra value.
+        if (isAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
+        }
+
         return new InputMethodSubtypeBuilder()
                 .setSubtypeNameResId(0)
                 .setSubtypeIconResId(0)
                 .setSubtypeLocale(locale)
                 .setSubtypeMode(mode)
-                .setSubtypeExtraValue("")
+                .setSubtypeExtraValue(subtypeExtraValue.toString())
                 .setIsAuxiliary(isAuxiliary)
                 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
                 .setIsAsciiCapable(isAsciiCapable)
@@ -253,10 +688,12 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
                     "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -268,33 +705,39 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
                     "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
                     "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
                     "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme",
                     "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -321,7 +764,8 @@
             final boolean isDefaultIme = false;
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
-                    IS_AUTO, !IS_ASCII_CAPABLE));
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice",
                     "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
                     subtypes));
@@ -332,9 +776,11 @@
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             // TODO: This subtype should be marked as IS_ASCII_CAPABLE
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
                     "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -345,7 +791,8 @@
             final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
                     "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -356,7 +803,8 @@
             final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
                     "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -368,13 +816,17 @@
                     new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -385,9 +837,11 @@
             final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
                     "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
                     isDefaultIme, subtypes));
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 1e32d43..94e6469 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -396,4 +396,8 @@
   to: /distribute/googleplay/edu/index.html
 
 - from: /preview/google-play-services-wear.html
-  to: /training/building-wearables.html
\ No newline at end of file
+  to: /training/building-wearables.html
+
+# ---------- DISTRIBUTE ------------------
+- from /distribute/tools/promote/badge-files.html
+  to: /distribute/tools/promote/badges.html
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 1a92753..75f541a 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -536,7 +536,7 @@
 </p>
 
 <p> For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <h3 id="xxxhdpi-launcher">Provide an xxx-high-density launcher icon</h3>
 
diff --git a/docs/html/distribute/tools/promote/badge-files.jd b/docs/html/distribute/tools/promote/badge-files.jd
deleted file mode 100644
index e65e698..0000000
--- a/docs/html/distribute/tools/promote/badge-files.jd
+++ /dev/null
@@ -1,289 +0,0 @@
-page.title=Google Play Badge Files
-page.image=/images/gp-badges-set.png
-page.metaDescription=Download hi-res assets for localized Google Play badges.
-page.tags="badge, google play"
-
-@jd:body
-
-<style>
-table tr td {border:0}
-</style>
-
-<p>The following links provide the Adobe&reg; Illustrator&reg; (.ai) file for the
-two Google Play badges.</p>
-
-
-<img src="{@docRoot}images/brand/en_generic_rgb_wo_60.png" alt="Get It On Google Play">
-
-<div style="clear:left">&nbsp;</div>
-
-<div class="col-4" style="margin-left:0">
-
-       <a href="{@docRoot}downloads/brand/v2/english_get.ai">English (English)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/af_generic_rgb_wo.ai">Afrikaans (Afrikaans)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/amharic_get.ai">ኣማርኛ (Amharic)</a><br/>
-
-<!--
-       <a href="{@docRoot}downloads/brand/ar_generic_rgb_wo.ai">العربية (Arabic)</a><br/>
--->
-       <a href="{@docRoot}downloads/brand/v2/belarusian_get.ai">Беларуская (Belarusian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/bulgarian_get.ai">български (Bulgarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/catalan_get.ai">Català (Catalan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_get.ai">中文 (中国) (Chinese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_get.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_get.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/croatian_get.ai">Hrvatski (Croatian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/czech_get.ai">Česky (Czech)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/danish_get.ai">Dansk (Danish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/dutch_get.ai">Nederlands (Dutch)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/estonian_get.ai">Eesti keel (Estonian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/farsi_get.ai">فارسی (Farsi Persian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/filipino_get.ai">Tagalog (Filipino)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/finnish_get.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
-       <a href="{@docRoot}downloads/brand/v2/french_get.ai">Français (French)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/german_get.ai">Deutsch (German)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/greek_get.ai">Ελληνικά (Greek)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hebrew_get.ai">עברית (Hebrew)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hindi_get.ai">हिन्दी (Hindi)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hungarian_get.ai">Magyar (Hungarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/indonesian_get.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/italian_get.ai">Italiano (Italian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/japanese_get.ai">日本語 (Japanese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/kazakh_get.ai">Қазақ тілі (Kazakh)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/korean_get.ai">한국어 (Korean)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/latvian_get.ai">Latviski (Latvian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/lithuanian_get.ai">Lietuviškai (Lithuanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/malay_get.ai">Bahasa Melayu (Malay)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/norwegian_get.ai">Norsk (Norwegian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/polish_get.ai">Polski (Polish)</a><br/>
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
-       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_get.ai">Português (Portuguese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_get.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/romanian_get.ai">Românã (Romanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/russian_get.ai">Pусский (Russian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/serbian_get.ai">Српски / srpski (Serbian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovak_get.ai">Slovenčina (Slovak)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovenian_get.ai">Slovenščina (Slovenian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/spanish_get.ai">Español (Spanish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_latam_get.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swahili_get.ai">Kiswahili (Swahili)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swedish_get.ai">Svenska (Swedish)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/thai_get.ai">ภาษาไทย (Thai)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/turkish_get.ai">Türkçe (Turkish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/uk_generic_rgb_wo.ai">Українська (Ukrainian)</a><br/>
-       <a href="{@docRoot}downloads/brand/vi_generic_rgb_wo.ai">Tiếng Việt (Vietnamese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/zulu_get.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left">&nbsp;</div>
-
-
-
-
-
-
-
-
-
-
-<img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="Android App On Google Play">
-
-<div style="clear:left">&nbsp;</div>
-
-<div class="col-4" style="margin-left:0">
-
-       <a href="{@docRoot}downloads/brand/v2/english_app.ai">English (English)</a><br/>
-      
-       <a href="{@docRoot}downloads/brand/v2/afrikaans_app.ai">Afrikaans (Afrikaans)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/amharic_app.ai">ኣማርኛ (Amharic)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/arabic_app.ai">العربية (Arabic)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/belarusian_app.ai">Беларуская (Belarusian)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/bulgarian_app.ai">български (Bulgarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/catalan_app.ai">Català (Catalan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/traditional_chinese_app.ai">中文 (中国) (Chinese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hongkong_chinese_app.ai">中文(香港) (Chinese Hong Kong)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/taiwan_chinese_app.ai">中文 (台灣) (Chinese Taiwan)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/croatian_app.ai">Hrvatski (Croatian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/czech_app.ai">Česky (Czech)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/danish_app.ai">Dansk (Danish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/dutch_app.ai">Nederlands (Dutch)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/estonian_app.ai">Eesti keel (Estonian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/farsi_app.ai">فارسی (Farsi Persian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/filipino_app.ai">Tagalog (Filipino)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/finnish_app.ai">Suomi (Finnish)</a><br/>
-
-</div>
-
-<div class="col-4">
-
-       <a href="{@docRoot}downloads/brand/v2/french_app.ai">Français (French)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/german_app.ai">Deutsch (German)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/greek_app.ai">Ελληνικά (Greek)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hebrew_app.ai">עברית (Hebrew)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hindi_app.ai">हिन्दी (Hindi)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/hungarian_app.ai">Magyar (Hungarian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/indonesian_app.ai">Bahasa Indonesia (Indonesian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/italian_app.ai">Italiano (Italian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/japanese_app.ai">日本語 (Japanese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/korean_app.ai">한국어 (Korean)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/latvian_app.ai">Latviski (Latvian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/lithuanian_app.ai">Lietuviškai (Lithuanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/malay_app.ai">Bahasa Melayu (Malay)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/norwegian_app.ai">Norsk (Norwegian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/polish_app.ai">Polski (Polish)</a><br/>
-
-
-</div>
-
-<div class="col-4" style="margin-right:0">
-
-       <a href="{@docRoot}downloads/brand/v2/portugal_portuguese_app.ai">Português (Portuguese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/brazilian_portuguese_app.ai">Português Brasil (Portuguese Brazil)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/romanian_app.ai">Românã (Romanian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/russian_app.ai">Pусский (Russian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/serbian_app.ai">Српски / srpski (Serbian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovak_app.ai">Slovenčina (Slovak)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/slovenian_app.ai">Slovenščina (Slovenian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_app.ai">Español (Spanish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/spanish_latam_app.ai">Español Latinoamérica (Spanish Latin America)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swahili_app.ai">Kiswahili (Swahili)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/swedish_app.ai">Svenska (Swedish)</a><br/>
-       
-       <a href="{@docRoot}downloads/brand/v2/thai_app.ai">ภาษาไทย (Thai)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/turkish_app.ai">Türkçe (Turkish)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/ukranian_app.ai">Українська (Ukrainian)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/vietnamese_app.ai">Tiếng Việt (Vietnamese)</a><br/>
-
-       <a href="{@docRoot}downloads/brand/v2/zulu_app.ai">isiZulu (Zulu)</a><br/>
-
-</div>
-<div style="clear:left">&nbsp;</div>
-
-
-
-
-
-  
-<h2>Guidelines</h2>
-
-  <ul>
-    <li>Do not modify the color, proportions, spacing or any other aspect of the badge image.
-    </li>
-    <li>When used alongside logos for other application marketplaces, the Google Play logo
-    should be of equal or greater size.</li>
-    <li>When used online, the badge should link to either:
-      <ul>
-        <li>A list of products published by you, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
-        </li>
-        <li>A specific app product details page within Google Play, for example:<br />
-        <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
-        </li>
-      </ul>
-    </li>
-  </ul>
-  
-<p>For more information, see the
-<a href="{@docRoot}distribute/tools/promote/brand.html#brand-google_play">Brand
-Guidelines</a>.
-
-
-<p>To quickly create a badge that links to your apps on Google Play,
-use the <a
-href="{@docRoot}distribute/tools/promote/badges.html">Googe Play badge generator</a>.</p>
diff --git a/docs/html/distribute/tools/promote/brand.jd b/docs/html/distribute/tools/promote/brand.jd
index 22441df..a12e753 100644
--- a/docs/html/distribute/tools/promote/brand.jd
+++ b/docs/html/distribute/tools/promote/brand.jd
@@ -5,7 +5,7 @@
 
 @jd:body
 
-<p>We encourage you to use the Android and Google Play brands with your Android app
+<p>We encourage you to use the Android brand with your Android app
 promotional materials. You can use the icons and other assets on this page
 provided that you follow the guidelines.</p>
 
@@ -89,47 +89,9 @@
 
 <p>The custom typeface may not be used.</p>
 
-<h2 id="brand-google_play">Google Play</h2>
+<p>The following are guidelines for the Google Play brand.</p>
 
-
- <p>The following are guidelines for the Google Play brand
- and related assets.</p>
-
-<h4>Google Play in text</h4>
-
-<p>Always include a TM symbol on the first or most prominent instance of Google Play&trade;
-in text.</p>
-
-<p>When referring to the mobile experience, use "Google Play" unless the text is clearly
-instructional for the user. For example, a marketing headline might read "Download our
-games on Google Play&trade;," but instructional text would read "Download our games using the Google
-Play&trade; store app."
-
- <p>Any use of the Google Play name or icon needs to include this
-    attribution in your communication:</p>
-
-<blockquote><em>Google Play is a trademark of Google Inc.</em></blockquote>
-
-
-  <div style="float:right;width:96px;margin-left:30px;margin-top:-20px">
-     <img src="{@docRoot}images/brand/Google_Play_Store_96.png" alt="">
-    <p style="text-align:center">
-       <a href="{@docRoot}images/brand/Google_Play_Store_48.png">48x48</a> |
-       <a href="{@docRoot}images/brand/Google_Play_Store_96.png">96x96</a><br>
-       <a href="{@docRoot}images/brand/Google_Play_Store_600.png">600x576</a>
-       </p>
-  </div>
-
-<h4>Google Play store icon</h4>
-
-<p>You may use the Google Play store icon, but you may not modify it.</p>
-
-<p>As mentioned above, when referring to the Google Play store app in copy, use the full name:
-"Google Play store." However, when labeling the Google Play store icon directly, it's OK to use
-"Play Store" alone to accurately reflect the icon label as it appears on a device.</p>
-
-
-<h4>Google Play badge</h4>
+<h4>Google Play&#8482; Badges</h4>
 
   <div style="float:right;clear:right;width:172px;margin-left:30px">
     <img src="{@docRoot}images/brand/en_app_rgb_wo_60.png" alt="">
@@ -145,21 +107,21 @@
        <a href="{@docRoot}images/brand/en_generic_rgb_wo_60.png">172x60</a></p>
   </div>
 
-  <p>The "Get it on Google Play" and "Android App on Google Play" logos are
-    badges that you can use on your website and promotional materials, to point
-    to your products on Google Play. Additional Google Play badge formats and
+  <p>Use the "Get it on Google Play" and "Android App on Google Play" badges on your website and
+  promotional materials to point to your products on Google Play. These badges are both available
+  in over 40 languages. Additional Google Play badge formats and
     badges for music, books, magazines, movies, and TV shows are also available.
     Use the  <a
     href="https://support.google.com/googleplay/contact/brand_developer">Android
     and Google Play Brand Permissions Inquiry form</a> to request
     those badges.</p>
 
+  <p>Google Play badge guidelines:</p>
   <ul>
-    <li>Don't modify the color, proportions, spacing, or any other aspect of the badge image.
-    </li>
-    <li>When used alongside logos for other application marketplaces, the Google Play logo
+    <li>Don't modify the color, proportions, spacing, or any other aspect of the badge.</li>
+    <li>When used alongside logos for other application marketplaces, the Google Play badge
     should be of equal or greater size.</li>
-    <li>When used online, the badge should link to either:
+    <li>When used online, the badge should link to either:</li>
       <ul>
         <li>A list of products published by you, for example:<br />
         <span style="margin-left:1em;">http://play.google.com/store/search?q=<em>publisherName</em></span>
@@ -168,24 +130,62 @@
         <span style="margin-left:1em;">http://play.google.com/store/apps/details?id=<em>packageName</em></span>
         </li>
       </ul>
+    <li>You do not need to include a legal attribution if you are only using a Google Play badge.
+    However, keep in mind that:</li>
+     <ul>
+     <li>If you make any mention of Google Play or Android outside of the badge a legal attribution
+     must be included. </li>
+     <li>If you are including another app store’s legal attribution then include this legal
+     attribution:</li>
+      <ul>
+      <li>Google Play is a trademark of Google Inc.</li>
+      </ul>
     </li>
+    <li>Use of the Google Play badge does not need to be reviewed or approved by the Google Play
+    brand team unless the marketing campaign will have over 1 million impressions.</li>
   </ul>
 
   <p>To quickly create a badge that links to your apps on Google Play,
   use the <a
   href="{@docRoot}distribute/tools/promote/badges.html">Google Play badge generator</a>
-  (provides the badge in over 40 languages).</p>
-
-  <p>To create your own size, download an Adobe&reg; Illustrator&reg; (.ai) file for the
-  <a href="{@docRoot}distribute/tools/promote/badge-files.html">Google Play
-  badge in over 40 languages</a>.</p>
+  (badges available in over 40 languages).</p>
 
   <p>For details on all the ways that you can link to your product details page in Google Play,
     see <a href="{@docRoot}distribute/tools/promote/linking.html">Linking to your products</a>.</p>
 
+<h2 id="Marketing_Review">Google Play in Text</h2>
+
+<p>Any use of Google Play in text must be reviewed and approved by the Google Play brand team.
+Submit your marketing via the <a href="https://support.google.com/googleplay/contact/brand_developer">
+Android and Google Play Partner Brand Inquiry Form.</a></p>
+
+<p>Always include a ™ symbol on the first or most prominent instance of Google Play™ in text.</p>
+
+<p>When mentioning that a product is available on Google Play always say “on Google Play”</p>
+
+<ul>
+<li><span style="color:red">Incorrect</span>: Our app is now available from Google Play.</li>
+<li><span style="color:green">Correct</span>: Our app is now available on Google Play.</li>
+</ul>
+<br>
+<p>Only refer to Google Play as the Google Play™ store app in instructional text meant to inform a
+customer about how to find or download your product on Google Play.</p>
+
+<ul>
+<li><span style="color:red">Incorrect</span>:  Download our games using the Google Play™ store app.</li>
+<li><span style="color:green">Correct</span>: This is how you download our app using the Google
+Play™ store app.</li>
+</ul>
+<br>
+
+<p>Any use of the Google Play name in your marketing or communications needs to be accompanied by
+this legal attribution:</p>
+
+<p><em>Google Play is a trademark of Google Inc.</em></p>
+
 <h2 id="Marketing_Review">Marketing Reviews and Brand Inquiries</h2>
 
 <p>Use the <a
 href="https://support.google.com/googleplay/contact/brand_developer">Android
 and Google Play Brand Permissions Inquiry form</a> to submit any marketing
-reviews or brand inquires. Typical response time is at least one week.</p>
+reviews or brand inquires. Typical response time is at least one week.</p>
\ No newline at end of file
diff --git a/docs/html/distribute/tools/promote/device-art.jd b/docs/html/distribute/tools/promote/device-art.jd
index f583eb9..814177b 100644
--- a/docs/html/distribute/tools/promote/device-art.jd
+++ b/docs/html/distribute/tools/promote/device-art.jd
@@ -417,7 +417,7 @@
       }
 
       if (this.archived) {
-        deviceList = '.device-list.archived';
+        deviceList = '.device-list.archive';
       } else if (this.hidden) {
         deviceList = '.device-list.hidden';
       }
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index fc95c2b..6ae7c1a 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -75,7 +75,6 @@
 <dt><strong>Canonical registration ID</strong></dt>
 <dd>There may be situations where the server ends up with 2 registration IDs for the same device. If the GCM response contains a registration ID, simply replace the registration ID you have with the one provided. With this feature your application doesn't need to send the device ID to your server anymore. For more information, see <a href="adv.html#canonical">Advanced Topics</a>.</dd>
 </dl>
-<p>GCM also provides client and server <a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a> to make writing your code easier.</p>
 
 <h3 id="interop">Relationship between C2DM and GCM</h3>
 
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 7c963dd..b6f1c49 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -368,7 +368,7 @@
 mipmap-xxxhdpi, regardless of the screen resolution of the device where your app is installed. This
 behavior allows launcher apps to pick the best resolution icon for your app to display on the home
 screen. For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.
 </p>
 
 
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 98e7c96..fc79970 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -76,7 +76,7 @@
 directory names are important and are described in table 1.</p>
 
 <p class="note"><strong>Note:</strong> For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <p class="table-caption" id="table1"><strong>Table 1.</strong> Resource directories
 supported inside project {@code res/} directory.</p>
diff --git a/docs/html/images/tools/studio-inspections-config.png b/docs/html/images/tools/studio-inspections-config.png
new file mode 100644
index 0000000..e41afa1
--- /dev/null
+++ b/docs/html/images/tools/studio-inspections-config.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index af6f6b8..a43ba3c 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,27 +4,27 @@
 header.hide=1
 page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
 
-studio.version=1.0.1
+studio.version=1.1.0
 
-studio.linux_bundle_download=android-studio-ide-135.1641136-linux.zip
-studio.linux_bundle_bytes=243917559
-studio.linux_bundle_checksum=7c8f2d0cec21b98984cdba45ab5a25f26d67f23a
+studio.linux_bundle_download=android-studio-ide-135.1740770-linux.zip
+studio.linux_bundle_bytes=259336386
+studio.linux_bundle_checksum=e8d166559c50a484f83ebfec6731cc0e3f259208
 
-studio.mac_bundle_download=android-studio-ide-1641136.dmg
-studio.mac_bundle_bytes=245729073
-studio.mac_bundle_checksum=49506ba2cf6b56be4f7d07e6a00c4ec3ba2249d5
+studio.mac_bundle_download=android-studio-ide-135.1740770-mac.dmg
+studio.mac_bundle_bytes=261303345
+studio.mac_bundle_checksum=f9745d0fec1eefd498f6160a2d6a1b5247d4cda3
 
-studio.win_bundle_exe_download=android-studio-bundle-135.1641136.exe
-studio.win_bundle_exe_bytes=868344232
-studio.win_bundle_exe_checksum=9c1c8ea6aa17fb74e0593c62fd48ee62a8950be7
+studio.win_bundle_exe_download=android-studio-bundle-135.1740770-windows.exe
+studio.win_bundle_exe_bytes=856233768
+studio.win_bundle_exe_checksum=7484b9989d2914e1de30995fbaa97a271a514b3f
 
-studio.win_notools_exe_download=android-studio-ide-135.1641136.exe
-studio.win_notools_exe_bytes=260272840
-studio.win_notools_exe_checksum=464d1c5497ab3d1bdef441365791ab36c89cd5ae
+studio.win_notools_exe_download=android-studio-ide-135.1740770-windows.exe
+studio.win_notools_exe_bytes=242135128
+studio.win_notools_exe_checksum=5ea77661cd2300cea09e8e34f4a2219a0813911f
 
-studio.win_bundle_download=android-studio-ide-135.1641136-windows.zip
-studio.win_bundle_bytes=246249059
-studio.win_bundle_checksum=6d6856aca83f6ff747ca40b10f70edfbbcccd91c
+studio.win_bundle_download=android-studio-ide-135.1740770-windows.zip
+studio.win_bundle_bytes=261667054
+studio.win_bundle_checksum=e903f17cc6a57c7e3d460c4555386e3e65c6b4eb
 
 
 
diff --git a/docs/html/tools/debugging/debugging-ui.jd b/docs/html/tools/debugging/debugging-ui.jd
index f927d08..cf7e3ba 100644
--- a/docs/html/tools/debugging/debugging-ui.jd
+++ b/docs/html/tools/debugging/debugging-ui.jd
@@ -34,17 +34,17 @@
       <h2>Related videos</h2>
           <ol>
               <li>
-<iframe title="Hierarchyviewer" 
-    width="210" height="160" 
-    src="//www.youtube.com/embed/PAgE7saQUUY?rel=0&amp;hd=1" 
+<iframe title="Hierarchyviewer"
+    width="210" height="160"
+    src="//www.youtube.com/embed/PAgE7saQUUY?rel=0&amp;hd=1"
     frameborder="0" allowfullscreen>
 </iframe>
               </li>
               <li>
-<iframe title="Pixel Perfect" 
-    width="210" height="160" 
-    src="//www.youtube.com/embed/C45bMZGdN7Y?rel=0&amp;hd=1" 
-    frameborder="0" 
+<iframe title="Pixel Perfect"
+    width="210" height="160"
+    src="//www.youtube.com/embed/C45bMZGdN7Y?rel=0&amp;hd=1"
+    frameborder="0"
     allowfullscreen>
 </iframe>
               </li>
@@ -52,11 +52,10 @@
     </div>
   </div>
 
-  <p>
-Sometimes your application's layout can slow down your application.
-  To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and
-  <code>lint</code> tools.
-  </p>
+
+<p>Sometimes your application's layout can slow down your application.
+To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and
+<code><a href="{@docRoot}tools/help/lint.html">lint</a></code> tools. </p>
 
   <p>The Hierarchy Viewer application allows you to debug and optimize your user interface. It
   provides a visual representation of the layout's View hierarchy (the View Hierarchy window)
@@ -64,8 +63,10 @@
   and a magnified view of the display (the Pixel Perfect window) to closely examine the pixels
   in your layout.</p>
 
-  <p>Android <code>lint</code> is a static code scanning tool that helps you optimize the layouts and layout
-  hierarchies of your applications, as well as detect other common coding problems. You can run it against your layout files or resource
+  <p>Android <code><a href="{@docRoot}tools/help/lint.html">lint</a></code> is a static code
+  scanning tool that helps you optimize the layouts and layout
+  hierarchies of your applications, as well as detect other common coding problems. You can run it
+  against your layout files or resource
   directories to quickly check for inefficiencies or other types of problems that could be
   affecting the performance of your application.</p>
 
@@ -493,7 +494,10 @@
         alt=""
         height="600"/>
 <p class="img-caption"><strong>Figure 4.</strong> The Pixel Perfect window</p>
+
+
 <h2 id="lint">Using lint to Optimize Your UI</h2>
-<p>The Android {@code lint} tool lets you analyze the XML files that define your application's UI to find inefficiencies in the view hierarchy.</p>
-<p class="note"><strong>Note: </strong>The Android <code>layoutopt</code> tool has been replaced by the {@code lint} tool beginning in ADT and SDK Tools revision 16. The {@code lint} tool reports UI layout performance issues in a similar way as <code>layoutopt</code>, and detects additional problems.</p>
-<p>For more information about using {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a> and the <a  href="{@docRoot}tools/help/lint.html">lint reference documentation</a>.</p>
+<p>The Android <a href="{@docRoot}tools/help/lint.html">lint</a> tool lets you analyze the XML
+files that define your application's UI to find inefficiencies in the view hierarchy.</p>
+<p class="note"><strong>Note: </strong>The Android <code>layoutopt</code> tool has been replaced by the {@code lint} tool beginning in SDK Tools revision 16. The {@code lint} tool reports UI layout performance issues in a similar way as <code>layoutopt</code>, and detects additional problems.</p>
+<p>For more information about using {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a> and the <a  href="{@docRoot}tools/help/lint.html">lint tools help</a>.</p>
diff --git a/docs/html/tools/debugging/improving-w-lint.jd b/docs/html/tools/debugging/improving-w-lint.jd
index 7e238fa..ff94b7f 100644
--- a/docs/html/tools/debugging/improving-w-lint.jd
+++ b/docs/html/tools/debugging/improving-w-lint.jd
@@ -9,11 +9,11 @@
 
       <ol>
         <li><a href="#overview">Overview</a></li>
-        <li><a href=#eclipse">Running lint from Eclipse</a></li>
+        <li><a href=#studio">Running lint from Android Studio</a></li>
         <li><a href=#commandline">Running lint from the command-line</a></li>
          <li><a href=#config">Configuring lint</a>
             <ol>
-		<LI><a href="#eclipse_config">Configuring lint in Eclipse</a></LI>
+		<LI><a href="#studio_config">Configuring lint in Android Studio</a></LI>
                 <LI><a href="#pref">Configuring the lint file</a></LI>
                 <LI><a href="#src">Configuring lint checking in Java and XML source files</a></LI>
             </ol>
@@ -31,8 +31,15 @@
 In addition to testing that your Android application meets its functional requirements, it's important to ensure that your code has no structural problems. Poorly structured code can impact the reliability and efficiency of your Android apps and make your code harder to maintain. For example, if your XML resource files contain unused namespaces, this takes up space and incurs unnecessary processing. Other structural issues, such as use of deprecated elements or API calls that are not supported by the target API versions, might lead to code failing to run correctly.</p>
 
 <h2 id="overview">Overview</h2>
-<p>The Android SDK provides a code scanning tool called {@code lint} that can help you to easily identify and correct problems with the structural quality of your code, without having to execute the app or write any test cases. Each problem detected by the tool is reported with a description message and a severity level, so that you can quickly prioritize the critical improvements that need to be made.  You can also configure a problem's severity level to ignore issues that are not relevant for your project, or raise the severity level. The tool has a command-line interface, so you can easily integrate it into your automated testing process.</p>
-<p>The {@code lint} tool checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. You can run {@code lint} from the command-line or from the Eclipse environment.</p>
+<p>The Android SDK provides a code scanning tool called <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a>
+that can help you to easily identify and correct problems with the structural quality of your code, without having to execute the app or write any test cases. Each problem detected by the tool is reported with a description message and a severity level, so that you can quickly prioritize the critical improvements that need to be made.  You can also configure a problem's severity level to ignore issues that are not relevant for your project, or raise the severity level. The tool has a command-line interface, so you can easily integrate it into your automated testing process.</p>
+<p>The {@code lint} tool checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. You can run {@code lint} from the command-line or from Android Studio.</p>
+
+<p class="note"><strong>Note:</strong> In Android Studio, additional
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a> run when your code is compiled in Android Studio to
+streamline code review.</p>
+
 <p>Figure 1 shows how the {@code lint} tool processes the application source files.</p>
 <img id="Fig1" src="{@docRoot}images/tools/lint.png" alt="">
 <p class="img-caption"><strong>Figure 1.</strong> Code scanning workflow with the {@code lint} tool</p>
@@ -42,25 +49,51 @@
 <dt><b>The <code>lint.xml</code> file</b></dt>
 <dd>A configuration file that you can use to specify any {@code lint} checks that you want to exclude and to customize problem severity levels.</dd>
 <dt><b>The {@code lint} tool</b></dt>
-<dd>A static code scanning tool that you can run on your Android project from the command-line or from Eclipse.   The {@code lint} tool checks for structural code problems that could affect the quality and performance of your Android application. It is strongly recommended that you correct any errors that {@code lint} detects before publishing your application.</dd>
+<dd>A static code scanning tool that you can run on your Android project from the command-line or Android Studio.  The {@code lint} tool checks for structural code problems that could affect the quality and performance of your Android application. It is strongly recommended that you correct any errors that {@code lint} detects before publishing your application.</dd>
 <dt><b>Results of {@code lint} checking</b></dt>
-<dd>You can view the results from {@code lint} in the console or in the <strong>Lint Warnings</strong> view in Eclipse.  Each issue is identified by the location in the source files where it occurred and a description of the issue.</dd>
+<dd>You can view the results from {@code lint} in the console or in the <strong>Event Log</strong> in Android Studio.  Each issue is identified by the location in the source files where it occurred and a description of the issue.</dd>
 </dl>
-<p>The {@code lint} tool is automatically installed as part of the Android SDK Tools revision 16 or higher. If you want to use {@code lint} in the Eclipse environment, you must also install the Android Development Tools (ADT) Plugin for Eclipse revision 16 or higher. For more information about installing the SDK or the ADT Plugin for Eclipse, see <a href="http://developer.android.com/sdk/installing.html">Installing the SDK.</a></p>
+<p>The {@code lint} tool is automatically installed as part of the Android SDK Tools revision 16 or higher.</p>
 
-<h2 id="eclipse">Running lint from Eclipse</h2>
-<p>If the ADT Plugin is installed in your Eclipse environment, the {@code lint} tool runs automatically when you perform one of these actions:</p>
-<ul>
-<LI>Export an APK</LI>
-<LI>Edit and save an XML source file in your Android project (such as a manifest or layout file)</LI>
-<LI>Use the layout editor in Eclipse to make changes</LI>
-</ul>
-<p>Note that when you export an APK, {@code lint} only runs an automatic check for fatal errors and aborts the export if fatal errors are found. You can turn off this automatic checking from the <strong>Lint Error Checking</strong> page in Eclipse Preferences. </p>
-<p>The output is displayed in the <strong>Lint Warnings</strong> view. If the <strong>Lint Warnings</strong> view is not showing in the workbench, you can bring it up from the Eclipse menu by clicking <strong>Window &gt; Show View &gt; Other &gt;  Android &gt; Lint Warnings</strong>.</p>
-<p>Figure 2 shows an example of the output in the Lint Warnings view.</p>
-<img id="Fig2" src="{@docRoot}images/tools/lint_output.png" alt="">
-<p class="img-caption"><strong>Figure 2.</strong> Sample output in the <strong>Lint Warnings</strong> view</p>
-<p>You can also run a {@code lint} scan manually on your Android project in Eclipse by right-clicking on the project folder in the Package Explorer > <strong>Android Tools  &gt; Run Lint: Check for Common Errors</strong>.</p>
+
+<h2 id="studio">Running lint in Android Studio</h2>
+<p>In Android Studio, the configured <code>lint</code> and
+IDE inspections run automatically whenever you build your app. The IDE inspections are
+configured along with the {@code lint} checks to run
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a> to streamline code review.</p>
+
+<p class="note"><strong>Note:</strong> To view and modify inspection severity
+levels, use the <strong>File &gt; Settings &gt; Project Settings</strong> menu to open the
+<em>Inspection Configuration</em> page with a list of the supported inspections.</p>
+
+
+<p>With Android Studio, you can also run {@code lint} inspections for a specific build variant,
+or for all build variants from the <code>build.gradle</code> file. Add the
+<code>lintOptions</code> property to the <code>android</code> settings in the build file.
+This code snippet from a Gradle build file shows how to set the <code>quiet</code> option to
+<code>true</code> and the <code>abortOnError</code> option to <code>false</code>. </p>
+
+<pre>
+android {
+    lintOptions {
+       // set to true to turn off analysis progress reporting by lint
+       quiet true
+       // if true, stop the gradle build if errors are found
+       abortOnError false
+       // if true, only report errors
+       ignoreWarnings true
+       }
+       ...
+    }
+</pre>
+
+
+<p>To manually run inspections in Android Studio, from the application or right-click menu,
+choose <strong>Analyze &gt; Inspect Code</strong>. The <em>Specify Inspections Scope</em> dialog
+appears so you can specify the desired inspection scope and profile.</p>
+
+
 
 
 <h2 id="commandline">Running lint from the Command-Line</h2>
@@ -96,38 +129,45 @@
 <p>By default, when you run a {@code lint} scan, the tool checks for all issues that are supported by {@code lint}.  You can also restrict the issues for {@code lint} to check and assign the severity level for those issues. For example, you can disable {@code lint} checking for specific issues that are not relevant to your project and configure {@code lint} to report non-critical issues at a lower severity level.</p>
 <p>You can configure {@code lint} checking at different levels:</p>
 <ul>
-<LI>Globally, for all projects</LI>
-<li>Per project</li>
-<li>Per file</li>
-<li>Per Java class or method (by using the <code>&#64;SuppressLint</code> annotation), or per XML element (by using the <code>tools:ignore</code> attribute.</li>
+<LI>Globally, for the entire project</LI>
+<li>Per project module</li>
+<li>Per production module</li>
+<li>Per test module</li>
+<li>Per open files</li>
+<li>Per class hierarchy</li>
+<li>Per Version Control System (VCS) scopes</li>
 </ul>
 
-<h3 id="eclipse_config">Configuring lint in Eclipse</h3>
-<p>You can configure global, project-specific, and file-specific settings for {@code lint} from the Eclipse user interface.</p>
+<h3 id="studio_config">Configuring lint in Android Studio</h3>
+<p>Android Studio allows you to enable or disable individual inspections and configure
+project-global, directory-specific, and file-specific settings for {@code lint}.</p>
+
+<p>You can manage inspection profiles and configure inspection severity within Android Studio using
+the <strong>File &gt; Settings &gt; Project Settings</strong> menu to open the <em>Inspections</em>
+page with a list of the supported profiles and inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 3.</strong> Inspection Configuration</p> 
 
 <h4>Global preferences</h4>
 <ol>
-<LI>Open <strong>Window  &gt; Preferences  &gt; Android  &gt; Lint Error Checking</strong>.</LI>
-<li>Specify your preferences and click <b>OK</b>.</li>
-</ol>
-<p>These settings are applied by default when you run {@code lint} on your Android projects in Eclipse.</p>
+<li>To specify global project settings, select the project folder in the Project View and choose
+<strong>Analyze &gt; Inspect Code</strong>.</li>
 
-<h4>Project and file-specific preferences</h4>
-<ol>
-<LI>Run the {@code lint} tool on your project by right-clicking on your project folder in the Package Explorer and selecting  <strong>Android Tools &gt; Run Lint: Check for Common Errors</strong>. This action brings up the <strong>Lint Warnings</strong> view which displays a list of issues that {@code lint} detected in your project.</LI>
-<li>From the <strong>Lint Warnings</strong> view, use the toolbar options to configure {@code lint} preferences for individual projects and files in Eclipse. The options you can select include:
-<ul>
-<LI><b>Suppress this error with an annotation/attribute</b> - If the issue appears in a Java class, the {@code lint} tool adds a <code>&#64;SuppressLint</code> annotation to the method where the issue was detected.  If the issue appears in an {@code .xml} file, {@code lint} inserts a <code>tools:ignore</code> attribute to disable checking for the {@code lint} issue in this file.</LI>
-<LI><b>Ignore in this file</b> - Disables checking for this {@code lint} issue in this file.</LI>
-<li><b>Ignore in this project</b>  - Disables checking for this {@code lint} issue in this project.</li>
-<li><b>Always ignore</b> - Disables checking for this {@code lint} issue globally for all projects.</li>
-</ul>
-</li>
+<li>Specify your inspection scope and profile, and click <b>OK</b>.</li>
 </ol>
-<p>If you select the second or third option, the {@code lint} tool automatically generates a <code>lint.xml</code> file with these configuration settings in your Android application project folder.  </p>
+<p>The configured settings run the specified {@code lint} inspections. The {@code lint}
+inspections are also run whenever you build and run your Android project and modules.</p>
+
+<h4>Module and file-specific preferences</h4>
+<ol>
+<LI>Run the {@code lint} tool on your module by right-clicking on your module folder or file in the Project View and selecting  <strong>Analyze &gt; Inspect Code</strong>. This displays the {@code lint} inspection results
+with a list of issues that {@code lint} detected in your module.</LI>
+<li>From the <strong>Lint Warnings</strong> view, use the toolbar options to configure {@code lint} preferences for individual modules and files, and set the issue display options.</li>
+</ol>
+
 
 <h3 id="pref">Configuring the lint file</h3>
-<p>You can specify your {@code lint} checking preferences in the <code>lint.xml</code> file.  If you are creating this file manually, place it in the root directory of your Android project.  If you are configuring {@code lint} preferences in Eclipse, the <code>lint.xml</code> file is automatically created and added to your Android project for you.</p>
+<p>You can specify your {@code lint} checking preferences in the <code>lint.xml</code> file.  If you are creating this file manually, place it in the root directory of your Android project.  If you are configuring {@code lint} preferences in Android Studio, the <code>lint.xml</code> file is automatically created and added to your Android project for you.</p>
 <p>The <code>lint.xml</code> file consists of an enclosing <code>&lt;lint&gt;</code> parent tag that contains one or more children <code>&lt;issue&gt;</code> elements.  Each <code>&lt;issue&gt;</code> is identified by a unique <code>id</code> attribute value, which is defined by {@code lint}.</p>
 <pre>
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
@@ -165,12 +205,9 @@
 <h3 id="src">Configuring lint checking in Java and XML source files</h3>
 <p>You can disable {@code lint} checking from your Java and XML source files.</p>
 
-<p class="note"><strong>Tip: </strong>If you are using Eclipse, you can use the <strong>Quick Fix</strong> feature to automatically add the annotation or attribute to disable {@code lint} checking to your Java or XML source files:
-<ol>
-<LI>Open the Java or XML file that has a {@code lint} warning or error in an Eclipse editor.</LI>
-<LI>Move your cursor to the location in the file where is {@code lint} issue is found, then press <code>Ctrl+1</code> to bring up the <strong>Quick Fix</strong> pop-up.</LI>
-<li>From the <strong>Quick Fix</strong> pop-up, select the action to add an annotation or attribute to ignore the {@code lint} issue.</li>
-</ol>
+<p class="note"><strong>Tip: </strong>If you are using Android Studio, you can use the
+<strong>File &gt; Settings &gt; Project Settings &gt; Inspections</strong> feature to manage the
+{@code lint} checking to your Java or XML source files.
 </p>
 
 <h4>Configuring lint checking in Java</h4>
diff --git a/docs/html/tools/help/lint.jd b/docs/html/tools/help/lint.jd
index ba31f6d..0f52689 100644
--- a/docs/html/tools/help/lint.jd
+++ b/docs/html/tools/help/lint.jd
@@ -14,14 +14,23 @@
   </div>
 </div>
 
-<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. </p>
-<p>For more information on running {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization.</p>
 
-<h2 id="syntax">Syntax</h2>
+<p>In Android Studio, the configured <code>lint</code> and other IDE inspections run automatically
+whenever you compile your program. You can also manually run inspections in Android Studio
+by selecting <strong>Analyze &gt; Inspect Code</strong> from the application or right-click menu.
+The <em>Specify Inspections Scope</em> dialog appears so you can specify the desired inspection 
+profile and scope.</p>
+
+<p>For more information on enabling {@code lint} inspections and running {@code lint},
+see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+
+<h2 id="syntax">Command Line Syntax</h2>
 <p>
 <pre>lint [flags] &lt;project directory&gt;</pre>
 
-For example, you can issue the following command to scan the Java and XML files under the {@code myproject}  directory and its subdirectories. The result is displayed on the console.
+For example, you can issue the following command to scan the Java and XML files under the
+{@code myproject}  directory and its subdirectories. The result is displayed on the console.
 <pre>lint myproject</pre>
 
 You can also use {@code lint} to check for a specific issue. For example, you can run the following command to scan the files under the {@code myproject} directory and its subdirectories to check for XML attributes missing the Android namespace prefix. The issue ID {@code MissingPrefix} tells lint to only scan for this issue.
@@ -172,7 +181,11 @@
 <h2 id="config_keywords">Configuring Java and XML Source Files</h2>
 <p>To configure lint checking, you can apply the following annotation or attribute to the source files in your Android project. </p>
 <ul>
-<LI>To disable lint checking for a specific Java class or method, use the <code>@SuppressLint</code> annotation. </LI>
-<li>To disable lint checking for specific sections of your XML file, use the <code>tools:ignore</code> attribute. </li>
+<LI>To disable {@code lint} checking for a specific Java class or method, use the <code>@SuppressLint</code>
+annotation. </LI>
+<li>To disable {@code lint} checking for specific sections of your XML file, use the
+<code>tools:ignore</code> attribute. </li>
 </ul>
-<p>You can also specify your lint checking preferences for a specific Android project in the lint.xml file.  For more information on configuring lint, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+<p>You can also specify your {@code lint} checking preferences for a specific Android project in
+the <code>lint.xml</code> file.  For more information on configuring {@code lint}, see
+<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
diff --git a/docs/html/tools/revisions/gradle-plugin.jd b/docs/html/tools/revisions/gradle-plugin.jd
index 23170e1..ebca5c7 100644
--- a/docs/html/tools/revisions/gradle-plugin.jd
+++ b/docs/html/tools/revisions/gradle-plugin.jd
@@ -40,7 +40,7 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
-      alt=""/>Android Plugin for Gradle, Revision 1.1</a> <em>(February 2015)</em>
+      alt=""/>Android Plugin for Gradle, Revision 1.1.0</a> <em>(February 2015)</em>
   </p>
 
   <div class="toggle-content-toggleme">
@@ -58,25 +58,59 @@
     <dt>General Notes:</dt>
     <dd>
     <ul>
-      <li>Fixed issue with Gradle build failure when accessing the
-      <code>extractReleaseAnnotations</code> module.
-      (<a href="http://b.android.com/81638">Issue 81638</a>).</li>
-      <li>Fixed debugging issue when displaying method input parameters at breakpoints.
-      (<a href="http://b.android.com/82031">Issue 82031</a>).</li>
-      <li>Fixed manifest merger issues when importing libraries with a <code>targetSdkVersion</code>
-      less than 16.</li>
-      <li>Fixed density ordering issue when using Android Studio with JDK 8.</li>
+      <li>Added new unit test support</li>
+      <ul>
+       <li>Enabled
+       <a href="{@docRoot}training/activity-testing/activity-unit-testing.html">unit tests</a> to
+       run on the local JVM against a special version of the <code>android.jar</code> file that is
+       compatible with popular mocking frameworks, for example Mockito. </li>
+       <li>Added new test tasks <code>testDebug</code>, <code>testRelease</code>, and
+       <code>testMyFlavorDebug</code> when using product flavors. </li>
+       <li>Added new source folders recognized as unit tests: <code>src/test/java/</code>,
+       <code>src/testDebug/java/</code>, <code>src/testMyFlavor/java/</code>.
+       <li>Added new configurations in the <code>build.gradle</code> file for declaring test-only
+       dependencies, for example, <code>testCompile 'junit:junit:4.11'</code>,
+       <code>testMyFlavorCompile 'some:library:1.0'</code>.
+        <p class="note"><strong>Note:</strong> Test-only dependencies are not currently compatible
+        with Jack (Java Android Compiler Kit). </p>
+       </li>
+       <li>Added the <code>android.testOptions.unitTests.returnDefaultValues</code> option to
+       control the behaviour of the mockable android.jar. </li>
+      </ul>
+      <li>Replaced <code>Test</code> in test task names with <code>AndroidTest</code>.
+      For example, the <code>assembleDebugTest</code> task is now
+      <code>assembleDebugAndroidTest</code> task. Unit test tasks still have <code>UnitTest</code>
+      in the task name, for example <code>assembleDebugUnitTest</code>. </li>
+      <li>Modified <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> configuration files to
+      no longer apply to the test APK. If minification is enabled, ProGuard processes the test APK
+      and applies only the mapping file that is generated when minifying the main APK. </li>
+      <li>Updated dependency management</li>
+       <ul>
+       <li>Fixed issues using <code>provided</code> and <code>package</code> scopes.
+         <p class="note"><strong>Note:</strong> These scopes are incompatible with AAR
+         (Android ARchive) packages and will cause a build with AAR packages to fail.</p>
+       </li>
+       <li>Modified dependency resolution to compare the dependencies of an app under test and the
+       test app. If an artifact with the same version is found for both apps, it's not included with
+       the test app and is packaged only with the app under test. If an artifact with a different
+       version is found for both apps, the build fails.</li>
+       </ul>
+
+      <li>Added support for <code>anyDpi</code>
+      <a href="{@docRoot}guide/topics/resources/providing-resources.html"> resource qualifier</a>
+      in resource merger. </li>
+      <li>Improved evaluation and IDE sync speeds for projects with a large number of
+      Android <a href="{@docRoot}sdk/installing/create-project.html#CreatingAModule"> modules</a>. </li>
     </ul>
     </dd>
   </div>
 </div>
 
 
-
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
-      alt=""/>Android Plugin for Gradle, Revision 1.0</a> <em>(December 2014)</em>
+      alt=""/>Android Plugin for Gradle, Revision 1.0.1</a> <em>(January 2015)</em>
   </p>
 
   <div class="toggle-content-toggleme">
@@ -86,7 +120,51 @@
 
     <dd>
       <ul>
-        <li>Gradle 2.2.1 or higher.</li>
+        <li>Gradle 2.2.1 up to 2.3.x.
+        <p class="note"><strong>Note:</strong> This version of the Android Plugin for Gradle is
+        not compatible with Gradle 2.4 and higher. </p>
+        </li>
+        <li>Build Tools 21.1.1 or higher.</li>
+      </ul>
+    </dd>
+
+    <dt>General Notes:</dt>
+    <dd>
+    <ul>
+      <li>Fixed issue with Gradle build failure when accessing the
+      <code>extractReleaseAnnotations</code> module.
+      (<a href="http://b.android.com/81638">Issue 81638</a>).</li>
+      <li>Fixed issue with <code>Disable</code> passing the
+      <code>--no-optimize</code> setting to the Dalvik Executable (dex) bytecode.
+      (<a href="http://b.android.com/82662">Issue 82662</a>).</li>
+      <li>Fixed manifest merger issues when importing libraries with a
+      <code>targetSdkVersion</code> less than 16.</li>
+      <li>Fixed density ordering issue when using Android Studio with JDK 8.</li>
+    </ul>
+    </dd>
+  </div>
+</div>
+
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
+      alt=""/>Android Plugin for Gradle, Revision 1.0.0</a> <em>(December 2014)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Gradle 2.2.1 up to 2.3.x.
+        <p class="note"><strong>Note:</strong> This version of the Android Plugin for Gradle is
+        not compatible with Gradle 2.4 and higher. </p>
+        </li>
         <li>Build Tools 21.1.1 or higher.</li>
       </ul>
     </dd>
diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd
index 26fe3cd..1860feb 100644
--- a/docs/html/tools/studio/index.jd
+++ b/docs/html/tools/studio/index.jd
@@ -36,7 +36,7 @@
   <li>Build variants and multiple <code>apk</code> file generation</li>
   <li>Code templates to help you build common app features</li>
   <li>Rich layout editor with support for drag and drop theme editing</li>
-  <li>Lint tools to catch performance, usability, version compatibility, and other problems</li>
+  <li>{@code lint} tools to catch performance, usability, version compatibility, and other problems</li>
   <li>ProGuard and app-signing capabilities</li>
   <li>Built-in support for <a
   href="http://developers.google.com/cloud/devtools/android_studio_templates/"
@@ -96,10 +96,9 @@
 <p>For example, <em>Android</em> project view groups all the instances of the
 <code>ic_launcher.png</code> resource for different screen densities under the same element.</p>
 
-<p class="note"><strong>Note:</strong> The project structure on disk differs from this flattened 
-representation. To switch to back the segregated project view, select <strong>Project</strong> from
-the <strong>Project</strong drop-down. </p>
-
+<p class="note"><strong>Note:</strong> The project structure on disk differs from this flattened
+representation. To switch to back to the segregated project view, select <strong>Project</strong> from
+the <strong>Project</strong> drop-down. </p>
 
 
 <h3>Android Studio Project and Directory Structure</h3>
@@ -182,7 +181,7 @@
 <p class="note"><strong>Note:</strong> The <em>applicationId</em> is specified only in your
 build.gradle file, and not in the AndroidManifest.xml file.</p>
 
-<p>When using build variants, the build system enables you to to uniquely identify different
+<p>When using build variants, the build system enables you to uniquely identify different
 packages for each product flavors and build types. The application ID in the build type is added as
 a suffix to those specified for the product flavors. </p>
 
@@ -244,7 +243,7 @@
 
 
 
-<h3> Memory Monitor</h3>
+<h3>Memory Monitor</h3>
 <p>Android Studio provides a memory monitor view so you can more easily monitor your
 app's memory usage to find deallocated objects, locate memory leaks and track the amount of
 memory the connected device is using. With your app running on a device or emulator, click the
@@ -255,33 +254,81 @@
 
 
 
-<h3> Lint inspections</h3>
-<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project
-source files for potential bugs and optimization improvements. Choose the <strong>Analyze &gt; 
-Inspect Code</strong> to manually run the inspections. The {@code lint} settings icon in the
-Inspection display provides a complete list of the current inspections.</p>
+<h3>Code Inspections</h3>
+<p>In Android Studio, the configured <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a> and
+other IDE inspections run automatically whenever you compile your program. In addition to the
+configured {@code lint} checks, additional
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a>
+run to streamline code review.</p>
 
-<p>Hovering over a Lint error displays the full issue explanation inline for easy error
+
+<p>Android Studio enables several <code>lint</code> checks
+to ensure:
+<ul>
+  <li><code> Cipher.getInstance()</code> is used with safe values</li>
+  <li>In custom Views, the associated declare-styleable for the custom view uses the same
+  base name as the class name.</li>
+  <li>Security check for fragment injection.</li>
+  <li>Where ever property assignment no longer works as expected.</li>
+  <li>Gradle plugin version is compatible with the SDK.</li>
+  <li>Right to left validation </li>
+  <li>Required API version</li>
+  <li>many others</li>
+</ul>
+
+
+<p>Hovering over an inspection error displays the full issue explanation inline for easy error
 resolution. There is also a helpful hyperlink at the end of the error message for additional
 error information.</p>
 
-<p>With Android Studio, you can run Lint for a specific build variant, or for all build variants.
-You can configure Lint by adding a <em>lintOptions</em> property to the Android settings in the
-build.gradle file.  </p>
+<p>With Android Studio, you can also run {@code lint} inspections for a specific build variant, or
+for all build variants. You can configure the {@code lint} inspections that run by adding a
+<code>lintOptions</code> property to the Android settings in the <code>build.gradle</code>
+file.  </p>
 
-    <pre>
-    android {
-        lintOptions {
-           // set to true to turn off analysis progress reporting by lint
-           quiet true
-           // if true, stop the gradle build if errors are found
-           abortOnError false
-           // if true, only report errors
-           ignoreWarnings true
-    </pre>
+<pre>
+android {
+    lintOptions {
+       // set to true to turn off analysis progress reporting by lint
+       quiet true
+       // if true, stop the gradle build if errors are found
+       abortOnError false
+       // if true, only report errors
+       ignoreWarnings true
+    }
+</pre>
+
+
+<p>You can also manage inspection profiles and configure inspections within Android Studio.
+Choose <strong>File &gt; Settings &gt; Project Settings</strong>. The
+<em>Inspection Configuration</em> page appears with the supported inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 5.</strong> Inspection Configuration</p> 
+
+<p class="note"><strong>Note:</strong> If you wish to change the behavior of specific
+inspection notifications, you can change the inspection severity, for example from <em>warning</em>
+to <em>error</em>. </p>
+
+
+<p>To manually run inspections in Android Studio, choose <strong>Analyze &gt; Inspect Code</strong>.
+The <em>Inspections Scope</em> dialog appears so you can specify the desired inspection profile and scope.</p>
+
+
+
+<h4>Running Inspections from the command line</h4>
+<p>You can also run {@code lint} inspections from the command line in your SDK directory. </p>
+<pre>
+sdk$ lint [flags] <project directories>
+</pre>
+
+<p class="note"><strong>Note:</strong> The {@code lint} <strong>--show</strong> and <strong>--list</strong>
+flags can be used to display the available issues and explanations. </p>
+
 
 <p>For more information, see
-<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with Lint</a>.</p>
+<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with {@code lint}</a> and
+<a href="{@docRoot}tools/help/lint.html">lint tool</a>.</p>
 
 
 <h3>Dynamic layout preview</h3>
@@ -346,6 +393,7 @@
     <p>For easy cross-platform development, the Project Wizard provides new templates for
     creating your apps for Android Wear and TV. </p>
     <p><img src="{@docRoot}images/tools/studio-tvwearsupport.png"  />
+
       <p class="img-caption"><strong>Figure 10.</strong> Supported Form Factors</p>
     <p>During app creation, the Project Wizard also displays an API Level dialog to help you choose
     the best <em>minSdkVersion</em> for your project.</p>
@@ -519,7 +567,8 @@
 
 
 <h3 id="git-samples"> Easy access to Android code samples on GitHub</h3>
-<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or Welcome page
+<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or <em>Welcome</em> page
+
 provides seamless access to Google code samples on GitHub.</p>
     <p><img src="{@docRoot}images/tools/studio-samples-githubaccess.png" /></p>
     <p class="img-caption"><strong>Figure 13.</strong> Code Sample Access</p>
diff --git a/docs/html/training/improving-layouts/optimizing-layout.jd b/docs/html/training/improving-layouts/optimizing-layout.jd
index 520ce56..003e7a2 100644
--- a/docs/html/training/improving-layouts/optimizing-layout.jd
+++ b/docs/html/training/improving-layouts/optimizing-layout.jd
@@ -126,13 +126,15 @@
 
 <p>Most of this time difference is due to the use of {@code layout_weight} in the {@link
 android.widget.LinearLayout} design, which can slow down the speed of measurement. It is just one
-example of how each layout has appropriate uses and you should carefully consider whether using 
+example of how each layout has appropriate uses and you should carefully consider whether using
 layout weight is necessary.</p>
 
 
 <h2 id="Lint">Use Lint</h2>
 
-<p>It is always good practice to run the <a href="http://tools.android.com/tips/lint">Lint</a> tool on your layout files to search for possible view hierarchy optimizations. Lint has replaced the Layoutopt tool and has much greater functionality. Some examples of Lint <a
+<p>It is always good practice to run the <a href="{@docRoot}tools/help/lint.html">lint</a>
+tool on your layout files to search for possible view hierarchy optimizations. Lint has replaced
+the Layoutopt tool and has much greater functionality. Some examples of lint <a
 href="http://tools.android.com/tips/lint-checks">rules</a> are:</p>
 
 <ul>
@@ -143,11 +145,18 @@
 <li>Deep layouts - Layouts with too much nesting are bad for performance. Consider using flatter layouts such as {@link android.widget.RelativeLayout} or {@link android.widget.GridLayout} to improve performance. The default maximum depth is 10.</li>
 </ul>
 
-<p>Another benefit of Lint is that it is integrated into the Android Development Tools for Eclipse (ADT 16+). Lint automatically runs whenever you export an APK, edit and save an XML file or use the Layout Editor. To manually force Lint to run press the Lint button in the Eclipse toolbar.</p>
+<p>Another benefit of Lint is that it is integrated into Android Studio. Lint automatically runs 
+whenever you compile your program. With Android Studio, you can also run lint inspections for a
+specific build variant, or for all build variants. </p>
 
-<img src="{@docRoot}images/training/lint_icon.png" alt="" />
+<p>You can also manage inspection profiles and configure inspections within Android Studio with the
+<strong>File&gt;Settings&gt;Project Settings</strong> option. The Inspection Configuration page
+appears with the supported inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 5.</strong> Inspection Configuration</p> 
 
-<p>When used inside Eclipse, Lint has the ability to automatically fix some issues, provide suggestions for others and jump directly to the offending code for review. If you don’t use Eclipse for your development, Lint can also be run from the command line. More information about Lint is available at <a href="http://tools.android.com/tips/lint">tools.android.com</a>.</p>
+<p>Lint has the ability to automatically fix some issues, provide suggestions for others and jump
+directly to the offending code for review.</p>
 
 
 
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd
index 1fc5904..64e70fd 100644
--- a/docs/html/training/multiscreen/screendensities.jd
+++ b/docs/html/training/multiscreen/screendensities.jd
@@ -154,7 +154,7 @@
 <p class="note"><strong>Note:</strong> You should place all launcher icons in the
 <code>res/mipmap-[density]/</code> folders, rather than <code>drawable/</code> folders to ensure
 launcher apps use the best resolution icon. For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <p>For more tips and guidelines for creating icon assets for your application, see the <a
 href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Icon Design
diff --git a/docs/html/training/volley/request.jd b/docs/html/training/volley/request.jd
index d8ccab2..8a7dc62 100644
--- a/docs/html/training/volley/request.jd
+++ b/docs/html/training/volley/request.jd
@@ -85,7 +85,7 @@
 
 // Retrieves an image specified by the URL, displays it in the UI.
 ImageRequest request = new ImageRequest(url,
-    new Response.Listener<Bitmap>() {
+    new Response.Listener&lt;Bitmap&gt;() {
         &#64;Override
         public void onResponse(Bitmap bitmap) {
             mImageView.setImageBitmap(bitmap);
@@ -257,7 +257,7 @@
 String url = "http://my-json-feed";
 
 JsonObjectRequest jsObjRequest = new JsonObjectRequest
-        (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
+        (Request.Method.GET, url, null, new Response.Listener&lt;JSONObject&gt;() {
 
     &#64;Override
     public void onResponse(JSONObject response) {
diff --git a/docs/html/training/volley/simple.jd b/docs/html/training/volley/simple.jd
index 942c57f..ecb5fde 100644
--- a/docs/html/training/volley/simple.jd
+++ b/docs/html/training/volley/simple.jd
@@ -63,7 +63,7 @@
 
 // Request a string response from the provided URL.
 StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
-            new Response.Listener<String>() {
+            new Response.Listener&lt;String&gt;() {
     &#64;Override
     public void onResponse(String response) {
         // Display the first 500 characters of the response string.
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index 8fbedae..3fe5672 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -200,10 +200,11 @@
      * exception. Supported formats are:
      * #RRGGBB
      * #AARRGGBB
+     * or one of the following names:
      * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
      * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey',
-     * 'aqua', 'fuschia', 'lime', 'maroon', 'navy', 'olive', 'purple',
-     * 'silver', 'teal'
+     * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
+     * 'silver', 'teal'.
      */
     public static int parseColor(String colorString) {
         if (colorString.charAt(0) == '#') {
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index d2799e1..db94d89 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -20,15 +20,11 @@
 import android.annotation.Nullable;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.ColorFilter;
-import android.graphics.PorterDuff.Mode;
-import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
 import android.util.AttributeSet;
 import android.util.TypedValue;
-import android.util.Log;
 import android.os.SystemClock;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -41,35 +37,15 @@
 /**
  * @hide
  */
-public class AnimatedRotateDrawable extends Drawable implements Drawable.Callback, Runnable,
-        Animatable {
-    private static final String TAG = "AnimatedRotateDrawable";
-
+public class AnimatedRotateDrawable extends DrawableWrapper implements Runnable, Animatable {
     private AnimatedRotateState mState;
-    private boolean mMutated;
+
     private float mCurrentDegrees;
     private float mIncrement;
     private boolean mRunning;
 
     public AnimatedRotateDrawable() {
-        this(null, null);
-    }
-
-    private AnimatedRotateDrawable(AnimatedRotateState rotateState, Resources res) {
-        mState = new AnimatedRotateState(rotateState, this, res);
-        init();
-    }
-
-    private void init() {
-        final AnimatedRotateState state = mState;
-        mIncrement = 360.0f / state.mFramesCount;
-        final Drawable drawable = state.mDrawable;
-        if (drawable != null) {
-            drawable.setFilterBitmap(true);
-            if (drawable instanceof BitmapDrawable) {
-                ((BitmapDrawable) drawable).setAntiAlias(true);
-            }
-        }
+        this(new AnimatedRotateState(null), null);
     }
 
     @Override
@@ -131,8 +107,7 @@
 
     @Override
     public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        boolean changed = super.setVisible(visible, restart);
+        final boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (changed || restart) {
                 mCurrentDegrees = 0.0f;
@@ -144,123 +119,6 @@
         return changed;
     }
 
-    /**
-     * Returns the drawable rotated by this RotateDrawable.
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
-    }
-
-    @Override
-    protected boolean onLevelChange(int level) {
-        return mState.mDrawable.setLevel(level);
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        return mState.mDrawable.setState(state);
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
     @Override
     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
@@ -268,50 +126,27 @@
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.AnimatedRotateDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
         updateStateFromTypedArray(a);
+        verifyRequiredAttributes(a);
         a.recycle();
 
-        inflateChildElements(r, parser, attrs, theme);
+        updateLocalState();
+    }
 
-        init();
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
     }
 
     @Override
-    public void applyTheme(@Nullable Theme t) {
-        super.applyTheme(t);
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
 
         final AnimatedRotateState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(
-                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-
-        init();
-    }
-
-    private void updateStateFromTypedArray(TypedArray a) {
-        final AnimatedRotateState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
 
         if (a.hasValue(R.styleable.AnimatedRotateDrawable_pivotX)) {
             final TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
@@ -332,43 +167,35 @@
 
         final Drawable dr = a.getDrawable(R.styleable.AnimatedRotateDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
+    @Override
+    public void applyTheme(@Nullable Theme t) {
         final AnimatedRotateState state = mState;
+        if (state == null) {
+            return;
+        }
 
-        Drawable dr = null;
-        int outerDepth = parser.getDepth();
-        int type;
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            if ((dr = Drawable.createFromXmlInner(r, parser, attrs, theme)) == null) {
-                Log.w(TAG, "Bad element under <animated-rotate>: " + parser.getName());
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.AnimatedRotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
             }
         }
 
-        if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
 
-    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
-                || mState.mThemeAttrs[R.styleable.AnimatedRotateDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <animated-rotate> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
+        updateLocalState();
     }
 
     public void setFramesCount(int framesCount) {
@@ -380,25 +207,7 @@
         mState.mFrameDuration = framesDuration;
     }
 
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class AnimatedRotateState extends Drawable.ConstantState {
+    static final class AnimatedRotateState extends DrawableWrapper.DrawableWrapperState {
         Drawable mDrawable;
         int[] mThemeAttrs;
 
@@ -414,35 +223,20 @@
         private boolean mCanConstantState;
         private boolean mCheckedConstantState;
 
-        public AnimatedRotateState(AnimatedRotateState orig, AnimatedRotateDrawable owner,
-                Resources res) {
+        public AnimatedRotateState(AnimatedRotateState orig) {
+            super(orig);
+
             if (orig != null) {
-                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());
-                mThemeAttrs = orig.mThemeAttrs;
                 mPivotXRel = orig.mPivotXRel;
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
                 mPivotY = orig.mPivotY;
                 mFramesCount = orig.mFramesCount;
                 mFrameDuration = orig.mFrameDuration;
-                mCanConstantState = mCheckedConstantState = true;
             }
         }
 
         @Override
-        public Drawable newDrawable() {
-            return new AnimatedRotateDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new AnimatedRotateDrawable(this, res);
         }
@@ -467,4 +261,27 @@
             return mCanConstantState;
         }
     }
+
+    private AnimatedRotateDrawable(AnimatedRotateState state, Resources res) {
+        super(state, res);
+
+        mState = state;
+
+        updateLocalState();
+    }
+
+    private void updateLocalState() {
+        final AnimatedRotateState state = mState;
+        mIncrement = 360.0f / state.mFramesCount;
+
+        // Force the wrapped drawable to use filtering and AA, if applicable,
+        // so that it looks smooth when rotated.
+        final Drawable drawable = state.mDrawable;
+        if (drawable != null) {
+            drawable.setFilterBitmap(true);
+            if (drawable instanceof BitmapDrawable) {
+                ((BitmapDrawable) drawable).setAntiAlias(true);
+            }
+        }
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 2a17a60..17e5b0b 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -197,6 +197,11 @@
     }
 
     @Override
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        return mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection);
+    }
+
+    @Override
     public int getAlpha() {
         return mAnimatedVectorState.mVectorDrawable.getAlpha();
     }
@@ -237,12 +242,6 @@
         return super.setVisible(visible, restart);
     }
 
-    /** {@hide} */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mAnimatedVectorState.mVectorDrawable.setLayoutDirection(layoutDirection);
-    }
-
     @Override
     public boolean isStateful() {
         return mAnimatedVectorState.mVectorDrawable.isStateful();
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index e5b2b76..f3574e8 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -50,32 +50,36 @@
  * @attr ref android.R.styleable#ClipDrawable_gravity
  * @attr ref android.R.styleable#ClipDrawable_drawable
  */
-public class ClipDrawable extends Drawable implements Drawable.Callback {
-    private ClipState mState;
-    private final Rect mTmpRect = new Rect();
-
+public class ClipDrawable extends DrawableWrapper {
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
 
-    private boolean mMutated;
+    private static final int MAX_LEVEL = 10000;
+
+    private final Rect mTmpRect = new Rect();
+
+    private ClipState mState;
 
     ClipDrawable() {
-        this(null, null);
+        this(new ClipState(null), null);
     }
 
     /**
-     * @param orientation Bitwise-or of {@link #HORIZONTAL} and/or {@link #VERTICAL}
+     * Creates a new clip drawable with the specified gravity and orientation.
+     *
+     * @param drawable the drawable to clip
+     * @param gravity gravity constant (see {@link Gravity} used to position
+     *                the clipped drawable within the parent container
+     * @param orientation bitwise-or of {@link #HORIZONTAL} and/or
+     *                   {@link #VERTICAL}
      */
     public ClipDrawable(Drawable drawable, int gravity, int orientation) {
-        this(null, null);
+        this(new ClipState(null), null);
 
-        mState.mDrawable = drawable;
         mState.mGravity = gravity;
         mState.mOrientation = orientation;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
+        setDrawable(drawable);
     }
 
     @Override
@@ -84,39 +88,15 @@
         super.inflate(r, parser, attrs, theme);
 
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ClipDrawable);
-
-        // 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);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
     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 (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.ClipDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <clip> tag requires a 'drawable' attribute or "
@@ -124,292 +104,110 @@
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final ClipState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
-        state.mOrientation = a.getInt(R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
-        state.mGravity = a.getInt(R.styleable.ClipDrawable_gravity, state.mGravity);
+        state.mOrientation = a.getInt(
+                R.styleable.ClipDrawable_clipOrientation, state.mOrientation);
+        state.mGravity = a.getInt(
+                R.styleable.ClipDrawable_gravity, state.mGravity);
 
         final Drawable dr = a.getDrawable(R.styleable.ClipDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final ClipState state = mState;
-        if (state == null || state.mThemeAttrs == null) {
+        if (state == null) {
             return;
         }
 
-        final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
-        try {
-            updateStateFromTypedArray(a);
-            verifyRequiredAttributes(a);
-        } catch (XmlPullParserException e) {
-            throw new RuntimeException(e);
-        } finally {
-            a.recycle();
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ClipDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    // overrides from Drawable.Callback
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    // overrides from Drawable
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        // XXX need to adjust padding!
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        return mState.mDrawable.setState(state);
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
+        super.onLevelChange(level);
         invalidateSelf();
         return true;
     }
 
     @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds);
-    }
-
-    @Override
     public void draw(Canvas canvas) {
-
-        if (mState.mDrawable.getLevel() == 0) {
+        final Drawable dr = getDrawable();
+        if (dr.getLevel() == 0) {
             return;
         }
 
         final Rect r = mTmpRect;
         final Rect bounds = getBounds();
-        int level = getLevel();
+        final int level = getLevel();
+
         int w = bounds.width();
         final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
         if ((mState.mOrientation & HORIZONTAL) != 0) {
-            w -= (w - iw) * (10000 - level) / 10000;
+            w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
+
         int h = bounds.height();
         final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
         if ((mState.mOrientation & VERTICAL) != 0) {
-            h -= (h - ih) * (10000 - level) / 10000;
+            h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
         }
+
         final int layoutDirection = getLayoutDirection();
         Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
             canvas.save();
             canvas.clipRect(r);
-            mState.mDrawable.draw(canvas);
+            dr.draw(canvas);
             canvas.restore();
         }
     }
 
-    @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
-    /** @hide */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mState.mDrawable.setLayoutDirection(layoutDirection);
-        super.setLayoutDirection(layoutDirection);
-    }
-
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class ClipState extends ConstantState {
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
-
-        Drawable mDrawable;
-
+    static final class ClipState extends DrawableWrapper.DrawableWrapperState {
         int mOrientation = HORIZONTAL;
         int mGravity = Gravity.LEFT;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        ClipState(ClipState orig) {
+            super(orig);
 
-        ClipState(ClipState orig, ClipDrawable owner, Resources res) {
             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());
                 mOrientation = orig.mOrientation;
                 mGravity = orig.mGravity;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new ClipDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new ClipDrawable(this, res);
         }
-
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
-
-        boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
     }
 
     private ClipDrawable(ClipState state, Resources res) {
-        mState = new ClipState(state, this, res);
+        super(state, res);
+
+        mState = state;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index fa269e0..98767a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -39,6 +39,7 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.IntProperty;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
@@ -422,27 +423,41 @@
      * Returns the resolved layout direction for this Drawable.
      *
      * @return One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
-     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
-     *
-     * @hide
+     *         {@link android.view.View#LAYOUT_DIRECTION_RTL}
+     * @see #setLayoutDirection(int)
      */
     public int getLayoutDirection() {
         return mLayoutDirection;
     }
 
     /**
-     * Set the layout direction for this drawable. Should be a resolved direction as the
-     * Drawable as no capacity to do the resolution on his own.
+     * Set the layout direction for this drawable. Should be a resolved
+     * layout direction, as the Drawable as no capacity to do the resolution on
+     * its own.
      *
-     * @param layoutDirection One of {@link android.view.View#LAYOUT_DIRECTION_LTR},
-     *   {@link android.view.View#LAYOUT_DIRECTION_RTL}
-     *
-     * @hide
+     * @param layoutDirection the resolved layout direction for the drawable,
+     *                        either {@link android.view.View#LAYOUT_DIRECTION_LTR}
+     *                        or {@link android.view.View#LAYOUT_DIRECTION_RTL}
+     * @see #getLayoutDirection()
      */
-    public void setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
-        if (getLayoutDirection() != layoutDirection) {
+    public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
+        if (mLayoutDirection != layoutDirection) {
             mLayoutDirection = layoutDirection;
+            return onLayoutDirectionChange(layoutDirection);
         }
+        return false;
+    }
+
+    /**
+     * Called when the drawable's resolved layout direction changes.
+     *
+     * @param layoutDirection the new resolved layout direction
+     * @return true if the layout direction change has caused the appearance of
+     *         the drawable to change and it needs to be re-drawn
+     * @see #setLayoutDirection(int)
+     */
+    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) {
+        return false;
     }
 
     /**
@@ -553,14 +568,20 @@
      * Sets the bounds to which the hotspot is constrained, if they should be
      * different from the drawable bounds.
      *
-     * @param left
-     * @param top
-     * @param right
-     * @param bottom
+     * @param left position in pixels of the left bound
+     * @param top position in pixels of the top bound
+     * @param right position in pixels of the right bound
+     * @param bottom position in pixels of the bottom bound
+     * @see #getHotspotBounds(android.graphics.Rect)
      */
     public void setHotspotBounds(int left, int top, int right, int bottom) {}
 
-    /** @hide For internal use only. Individual results may vary. */
+    /**
+     * Populates {@code outRect} with the hotspot bounds.
+     *
+     * @param outRect the rect to populate with the hotspot bounds
+     * @see #setHotspotBounds(int, int, int, int)
+     */
     public void getHotspotBounds(Rect outRect) {
         outRect.set(getBounds());
     }
@@ -1351,5 +1372,20 @@
             default: return defaultMode;
         }
     }
+
+    /** @hide */
+    public static final IntProperty<Drawable> ALPHA = new IntProperty<Drawable>("alpha") {
+        @Override
+        public void setValue(Drawable object, int value) {
+            object.mutate();
+            object.setAlpha(value);
+            object.invalidateSelf();
+        }
+
+        @Override
+        public Integer get(Drawable object) {
+            return object.getAlpha();
+        }
+    };
 }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 557f563..c4794d9 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -173,7 +173,7 @@
 
     @Override
     public void setColorFilter(ColorFilter cf) {
-        mDrawableContainerState.mHasColorFilter = (cf != null);
+        mDrawableContainerState.mHasColorFilter = true;
 
         if (mDrawableContainerState.mColorFilter != cf) {
             mDrawableContainerState.mColorFilter = cf;
@@ -306,7 +306,6 @@
         }
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         if (mHotspotBounds != null) {
@@ -339,6 +338,13 @@
     }
 
     @Override
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        // Let the container handle setting its own layout direction. Otherwise,
+        // we're accessing potentially unused states.
+        return mDrawableContainerState.setLayoutDirection(layoutDirection, getCurrentIndex());
+    }
+
+    @Override
     public int getIntrinsicWidth() {
         if (mDrawableContainerState.isConstantSize()) {
             return mDrawableContainerState.getConstantWidth();
@@ -829,18 +835,25 @@
             return null;
         }
 
-        final void setLayoutDirection(int layoutDirection) {
+        final boolean setLayoutDirection(int layoutDirection, int currentIndex) {
+            boolean changed = false;
+
             // No need to call createAllFutures, since future drawables will
             // change layout direction when they are prepared.
             final int N = mNumChildren;
             final Drawable[] drawables = mDrawables;
             for (int i = 0; i < N; i++) {
                 if (drawables[i] != null) {
-                    drawables[i].setLayoutDirection(layoutDirection);
+                    final boolean childChanged = drawables[i].setLayoutDirection(layoutDirection);
+                    if (i == currentIndex) {
+                        changed = childChanged;
+                    }
                 }
             }
 
             mLayoutDirection = layoutDirection;
+
+            return changed;
         }
 
         final void applyTheme(Theme theme) {
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
new file mode 100644
index 0000000..b17bab0
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -0,0 +1,443 @@
+/*
+ * 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.graphics.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Insets;
+import android.graphics.Outline;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.io.IOException;
+import java.util.Collection;
+
+/**
+ * Drawable container with only one child element.
+ */
+public abstract class DrawableWrapper extends Drawable implements Drawable.Callback {
+    private DrawableWrapperState mState;
+    private Drawable mDrawable;
+    private boolean mMutated;
+
+    DrawableWrapper(DrawableWrapperState state, Resources res) {
+        mState = state;
+
+        updateLocalState(res);
+    }
+
+    /**
+     * Creates a new wrapper around the specified drawable.
+     *
+     * @param dr the drawable to wrap
+     */
+    public DrawableWrapper(@Nullable Drawable dr) {
+        mState = null;
+        mDrawable = dr;
+    }
+
+    /**
+     * 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 != null && mState.mDrawableState != null) {
+            final Drawable dr = mState.mDrawableState.newDrawable(res);
+            setDrawable(dr);
+        }
+    }
+
+    /**
+     * Sets the wrapped drawable.
+     *
+     * @param dr the wrapped drawable
+     */
+    public void setDrawable(@Nullable Drawable dr) {
+        if (mDrawable != null) {
+            mDrawable.setCallback(null);
+        }
+
+        mDrawable = dr;
+
+        if (dr != null) {
+            dr.setCallback(this);
+
+            // Only call setters for data that's stored in the base Drawable.
+            dr.setVisible(isVisible(), true);
+            dr.setState(getState());
+            dr.setLevel(getLevel());
+            dr.setBounds(getBounds());
+            dr.setLayoutDirection(getLayoutDirection());
+
+            if (mState != null) {
+                mState.mDrawableState = dr.getConstantState();
+            }
+        }
+
+        invalidateSelf();
+    }
+
+    /**
+     * @return the wrapped drawable
+     */
+    @Nullable
+    public Drawable getDrawable() {
+        return mDrawable;
+    }
+
+    void updateStateFromTypedArray(TypedArray a) {
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        // Account for any configuration changes.
+        state.mChangingConfigurations |= a.getChangingConfigurations();
+
+        // Extract the theme attributes, if any.
+        state.mThemeAttrs = a.extractThemeAttrs();
+
+        // TODO: Consider using R.styleable.DrawableWrapper_drawable
+    }
+
+    @Override
+    public void applyTheme(Resources.Theme t) {
+        super.applyTheme(t);
+
+        final DrawableWrapperState state = mState;
+        if (state == null) {
+            return;
+        }
+
+        if (mDrawable != null && mDrawable.canApplyTheme()) {
+            mDrawable.applyTheme(t);
+        }
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
+    }
+
+    @Override
+    public void invalidateDrawable(Drawable who) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.invalidateDrawable(this);
+        }
+    }
+
+    @Override
+    public void scheduleDrawable(Drawable who, Runnable what, long when) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.scheduleDrawable(this, what, when);
+        }
+    }
+
+    @Override
+    public void unscheduleDrawable(Drawable who, Runnable what) {
+        final Callback callback = getCallback();
+        if (callback != null) {
+            callback.unscheduleDrawable(this, what);
+        }
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        if (mDrawable != null) {
+            mDrawable.draw(canvas);
+        }
+    }
+
+    @Override
+    public int getChangingConfigurations() {
+        return super.getChangingConfigurations()
+                | (mState != null ? mState.mChangingConfigurations : 0)
+                | mDrawable.getChangingConfigurations();
+    }
+
+    @Override
+    public boolean getPadding(@NonNull Rect padding) {
+        return mDrawable != null && mDrawable.getPadding(padding);
+    }
+
+    /** @hide */
+    @Override
+    public Insets getOpticalInsets() {
+        return mDrawable != null ? mDrawable.getOpticalInsets() : Insets.NONE;
+    }
+
+    @Override
+    public void setHotspot(float x, float y) {
+        if (mDrawable != null) {
+            mDrawable.setHotspot(x, y);
+        }
+    }
+
+    @Override
+    public void setHotspotBounds(int left, int top, int right, int bottom) {
+        if (mDrawable != null) {
+            mDrawable.setHotspotBounds(left, top, right, bottom);
+        }
+    }
+
+    @Override
+    public void getHotspotBounds(@NonNull Rect outRect) {
+        if (mDrawable != null) {
+            mDrawable.getHotspotBounds(outRect);
+        } else {
+            outRect.set(getBounds());
+        }
+    }
+
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        final boolean superChanged = super.setVisible(visible, restart);
+        final boolean changed = mDrawable != null && mDrawable.setVisible(visible, restart);
+        return superChanged | changed;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        if (mDrawable != null) {
+            mDrawable.setAlpha(alpha);
+        }
+    }
+
+    @Override
+    public int getAlpha() {
+        return mDrawable != null ? mDrawable.getAlpha() : 255;
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter cf) {
+        if (mDrawable != null) {
+            mDrawable.setColorFilter(cf);
+        }
+    }
+
+    @Override
+    public void setTintList(@Nullable ColorStateList tint) {
+        if (mDrawable != null) {
+            mDrawable.setTintList(tint);
+        }
+    }
+
+    @Override
+    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+        if (mDrawable != null) {
+            mDrawable.setTintMode(tintMode);
+        }
+    }
+
+    @Override
+    public boolean onLayoutDirectionChange(@View.ResolvedLayoutDir int layoutDirection) {
+        return mDrawable != null && mDrawable.setLayoutDirection(layoutDirection);
+    }
+
+    @Override
+    public int getOpacity() {
+        return mDrawable != null ? mDrawable.getOpacity() : PixelFormat.TRANSPARENT;
+    }
+
+    @Override
+    public boolean isStateful() {
+        return mDrawable != null && mDrawable.isStateful();
+    }
+
+    @Override
+    protected boolean onStateChange(int[] state) {
+        if (mDrawable != null) {
+            final boolean changed = mDrawable.setState(state);
+            if (changed) {
+                onBoundsChange(getBounds());
+            }
+            return changed;
+        }
+        return false;
+    }
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        return mDrawable != null && mDrawable.setLevel(level);
+    }
+
+    @Override
+    protected void onBoundsChange(@NonNull Rect bounds) {
+        if (mDrawable != null) {
+            mDrawable.setBounds(bounds);
+        }
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mDrawable != null ? mDrawable.getIntrinsicWidth() : -1;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mDrawable != null ? mDrawable.getIntrinsicHeight() : -1;
+    }
+
+    @Override
+    public void getOutline(@NonNull Outline outline) {
+        if (mDrawable != null) {
+            mDrawable.getOutline(outline);
+        } else {
+            super.getOutline(outline);
+        }
+    }
+
+    @Override
+    @Nullable
+    public ConstantState getConstantState() {
+        if (mState != null && mState.canConstantState()) {
+            mState.mChangingConfigurations = getChangingConfigurations();
+            return mState;
+        }
+        return null;
+    }
+
+    @Override
+    @NonNull
+    public Drawable mutate() {
+        if (!mMutated && super.mutate() == this) {
+            mState = mutateConstantState();
+            if (mDrawable != null) {
+                mDrawable.mutate();
+            }
+            if (mState != null) {
+                mState.mDrawableState = mDrawable != null ? mDrawable.getConstantState() : null;
+            }
+            mMutated = true;
+        }
+        return this;
+    }
+
+    /**
+     * Mutates the constant state and returns the new state. Responsible for
+     * updating any local copy.
+     * <p>
+     * This method should never call the super implementation; it should always
+     * mutate and return its own constant state.
+     *
+     * @return the new state
+     */
+    DrawableWrapperState mutateConstantState() {
+        return mState;
+    }
+
+    /**
+     * @hide Only used by the framework for pre-loading resources.
+     */
+    public void clearMutated() {
+        super.clearMutated();
+        if (mDrawable != null) {
+            mDrawable.clearMutated();
+        }
+        mMutated = false;
+    }
+
+    /**
+     * Called during inflation to inflate the child element.
+     */
+    void inflateChildDrawable(Resources r, XmlPullParser parser, AttributeSet attrs,
+            Resources.Theme theme) throws XmlPullParserException, IOException {
+        // Drawable specified on the root element takes precedence.
+        if (getDrawable() != null) {
+            return;
+        }
+
+        // Seek to the first child element.
+        Drawable dr = null;
+        int type;
+        final int outerDepth = parser.getDepth();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.START_TAG) {
+                dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
+                break;
+            }
+        }
+
+        if (dr != null) {
+            setDrawable(dr);
+        }
+    }
+
+    abstract static class DrawableWrapperState extends Drawable.ConstantState {
+        int[] mThemeAttrs;
+        int mChangingConfigurations;
+
+        Drawable.ConstantState mDrawableState;
+
+        DrawableWrapperState(DrawableWrapperState orig) {
+            if (orig != null) {
+                mThemeAttrs = orig.mThemeAttrs;
+                mChangingConfigurations = orig.mChangingConfigurations;
+                mDrawableState = orig.mDrawableState;
+            }
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null
+                    || (mDrawableState != null && mDrawableState.canApplyTheme())
+                    || super.canApplyTheme();
+        }
+
+        @Override
+        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+            final Drawable.ConstantState state = mDrawableState;
+            if (state != null) {
+                return state.addAtlasableBitmaps(atlasList);
+            }
+            return 0;
+        }
+
+        @Override
+        public Drawable newDrawable() {
+            return newDrawable(null);
+        }
+
+        @Override
+        public abstract Drawable newDrawable(Resources res);
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+
+        public boolean canConstantState() {
+            return mDrawableState != null;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 50a6df4..b0cd386 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -18,27 +18,20 @@
 
 import com.android.internal.R;
 
-import android.annotation.NonNull;
-
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.res.ColorStateList;
+import android.annotation.NonNull;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
+import android.content.res.TypedArray;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 
 import java.io.IOException;
-import java.util.Collection;
 
 /**
  * A Drawable that insets another Drawable by a specified distance.
@@ -56,13 +49,10 @@
  * @attr ref android.R.styleable#InsetDrawable_insetTop
  * @attr ref android.R.styleable#InsetDrawable_insetBottom
  */
-public class InsetDrawable extends Drawable implements Drawable.Callback {
+public class InsetDrawable extends DrawableWrapper {
     private final Rect mTmpRect = new Rect();
 
     private InsetState mState;
-    private Drawable mDrawable;
-
-    private boolean mMutated;
 
     /**
      * No-arg constructor used by drawable inflation.
@@ -94,72 +84,29 @@
             int insetBottom) {
         this(new InsetState(), null);
 
-        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);
-        }
+        setDrawable(drawable);
     }
 
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
-        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
-        super.inflateWithAttributes(r, parser, a, R.styleable.InsetDrawable_visible);
+        super.inflate(r, parser, attrs, theme);
 
+        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.InsetDrawable);
         updateStateFromTypedArray(a);
-        inflateChildElements(r, parser, attrs, theme);
+        inflateChildDrawable(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 (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");
-            }
-
-            final Drawable dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-            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 (mDrawable == null && (mState.mThemeAttrs == null
+        if (getDrawable() == null && (mState.mThemeAttrs == null
                 || mState.mThemeAttrs[R.styleable.InsetDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <inset> tag requires a 'drawable' attribute or "
@@ -167,15 +114,11 @@
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final InsetState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
         final int N = a.getIndexCount();
         for (int i = 0; i < N; i++) {
             final int attr = a.getIndex(i);
@@ -183,7 +126,6 @@
                 case R.styleable.InsetDrawable_drawable:
                     final Drawable dr = a.getDrawable(attr);
                     if (dr != null) {
-                        mState.mDrawableState = dr.getConstantState();
                         setDrawable(dr);
                     }
                     break;
@@ -214,8 +156,6 @@
 
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final InsetState state = mState;
         if (state == null) {
             return;
@@ -233,55 +173,14 @@
             }
         }
 
-        if (mDrawable != null && mDrawable.canApplyTheme()) {
-            mDrawable.applyTheme(t);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        mDrawable.draw(canvas);
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mDrawable.getChangingConfigurations();
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
     @Override
     public boolean getPadding(Rect padding) {
-        final boolean pad = mDrawable.getPadding(padding);
+        final boolean pad = super.getPadding(padding);
 
         padding.left += mState.mInsetLeft;
         padding.right += mState.mInsetRight;
@@ -303,62 +202,9 @@
     }
 
     @Override
-    public void setHotspot(float x, float y) {
-        mDrawable.setHotspot(x, y);
-    }
-
-    @Override
-    public void setHotspotBounds(int left, int top, int right, int bottom) {
-        mDrawable.setHotspotBounds(left, top, right, bottom);
-    }
-
-    /** @hide */
-    @Override
-    public void getHotspotBounds(Rect outRect) {
-        mDrawable.getHotspotBounds(outRect);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mDrawable.setTintMode(tintMode);
-    }
-
-    /** {@hide} */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        mDrawable.setLayoutDirection(layoutDirection);
-    }
-
-    @Override
     public int getOpacity() {
         final InsetState state = mState;
-        final int opacity = mDrawable.getOpacity();
+        final int opacity = getDrawable().getOpacity();
         if (opacity == PixelFormat.OPAQUE && (state.mInsetLeft > 0 || state.mInsetTop > 0
                 || state.mInsetRight > 0 || state.mInsetBottom > 0)) {
             return PixelFormat.TRANSLUCENT;
@@ -367,23 +213,6 @@
     }
 
     @Override
-    public boolean isStateful() {
-        return mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        final boolean changed = mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
-    }
-
-    @Override
-    protected boolean onLevelChange(int level) {
-        return mDrawable.setLevel(level);
-    }
-
-    @Override
     protected void onBoundsChange(Rect bounds) {
         final Rect r = mTmpRect;
         r.set(bounds);
@@ -393,22 +222,23 @@
         r.right -= mState.mInsetRight;
         r.bottom -= mState.mInsetBottom;
 
-        mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+        // Apply inset bounds to the wrapped drawable.
+        super.onBoundsChange(r);
     }
 
     @Override
     public int getIntrinsicWidth() {
-        return mDrawable.getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
+        return getDrawable().getIntrinsicWidth() + mState.mInsetLeft + mState.mInsetRight;
     }
 
     @Override
     public int getIntrinsicHeight() {
-        return mDrawable.getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
+        return getDrawable().getIntrinsicHeight() + mState.mInsetTop + mState.mInsetBottom;
     }
 
     @Override
     public void getOutline(@NonNull Outline outline) {
-        mDrawable.getOutline(outline);
+        getDrawable().getOutline(outline);
     }
 
     @Override
@@ -421,33 +251,12 @@
     }
 
     @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState = new InsetState(mState);
-            mDrawable.mutate();
-            mState.mDrawableState = mDrawable.getConstantState();
-            mMutated = true;
-        }
-        return this;
+    DrawableWrapperState mutateConstantState() {
+        mState = new InsetState(mState);
+        return mState;
     }
 
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    /**
-     * Returns the drawable wrapped by this InsetDrawable. May be null.
-     */
-    public Drawable getDrawable() {
-        return mDrawable;
-    }
-
-    private static final class InsetState extends ConstantState {
+    static final class InsetState extends DrawableWrapper.DrawableWrapperState {
         int[] mThemeAttrs;
         int mChangingConfigurations;
 
@@ -458,15 +267,14 @@
         int mInsetRight = 0;
         int mInsetBottom = 0;
 
-        public InsetState() {
-            // Empty constructor.
+        InsetState() {
+            this(null);
         }
 
-        public InsetState(InsetState orig) {
+        InsetState(InsetState orig) {
+            super(orig);
+
             if (orig != null) {
-                mThemeAttrs = orig.mThemeAttrs;
-                mChangingConfigurations = orig.mChangingConfigurations;
-                mDrawableState = orig.mDrawableState;
                 mInsetLeft = orig.mInsetLeft;
                 mInsetTop = orig.mInsetTop;
                 mInsetRight = orig.mInsetRight;
@@ -475,39 +283,9 @@
         }
 
         @Override
-        public boolean 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);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new InsetDrawable(this, res);
         }
-
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
-
-        public boolean canConstantState() {
-            return mDrawableState != null;
-        }
     }
 
     /**
@@ -515,21 +293,9 @@
      * constructors to set the state and initialize local properties.
      */
     private InsetDrawable(InsetState state, Resources res) {
+        super(state, 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 616aebd..f5353d4 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -558,10 +558,9 @@
      * default layer gravity behavior. See {@link #setLayerGravity(int, int)}
      * for more information.
      *
-     * @param index the index of the drawable to adjust
+     * @param index the index of the layer 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
@@ -574,9 +573,18 @@
     }
 
     /**
+     * @param index the index of the layer to adjust
+     * @param w width in pixels, or -1 to use the intrinsic width
+     * @attr ref android.R.styleable#LayerDrawableItem_width
+     */
+    public void setLayerWidth(int index, int w) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mWidth = w;
+    }
+
+    /**
      * @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
      */
@@ -586,9 +594,18 @@
     }
 
     /**
+     * @param index the index of the layer to adjust
+     * @param h height in pixels, or -1 to use the intrinsic height
+     * @attr ref android.R.styleable#LayerDrawableItem_height
+     */
+    public void setLayerHeight(int index, int h) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mHeight = h;
+    }
+
+    /**
      * @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
      */
@@ -656,7 +673,7 @@
      * Specifies the relative insets in pixels for the drawable at the
      * specified index.
      *
-     * @param index the index of the drawable to adjust
+     * @param index the index of the layer 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
@@ -671,6 +688,126 @@
         setLayerInsetInternal(index, 0, t, 0, b, s, e);
     }
 
+    /**
+     * @param index the index of the layer to adjust
+     * @param l number of pixels to inset from the left bound
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     */
+    public void setLayerInsetLeft(int index, int l) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetL = l;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the left bound
+     * @attr ref android.R.styleable#LayerDrawableItem_left
+     */
+    public int getLayerInsetLeft(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetL;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param r number of pixels to inset from the right bound
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     */
+    public void setLayerInsetRight(int index, int r) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetR = r;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the right bound
+     * @attr ref android.R.styleable#LayerDrawableItem_right
+     */
+    public int getLayerInsetRight(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetR;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param t number of pixels to inset from the top bound
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     */
+    public void setLayerInsetTop(int index, int t) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetT = t;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the top bound
+     * @attr ref android.R.styleable#LayerDrawableItem_top
+     */
+    public int getLayerInsetTop(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetT;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param b number of pixels to inset from the bottom bound
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public void setLayerInsetBottom(int index, int b) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetB = b;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the bottom bound
+     * @attr ref android.R.styleable#LayerDrawableItem_bottom
+     */
+    public int getLayerInsetBottom(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetB;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param s number of pixels to inset from the start bound
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     */
+    public void setLayerInsetStart(int index, int s) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetS = s;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the start bound
+     * @attr ref android.R.styleable#LayerDrawableItem_start
+     */
+    public int getLayerInsetStart(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetS;
+    }
+
+    /**
+     * @param index the index of the layer to adjust
+     * @param e number of pixels to inset from the end bound
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     */
+    public void setLayerInsetEnd(int index, int e) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        childDrawable.mInsetE = e;
+    }
+
+    /**
+     * @param index the index of the layer
+     * @return number of pixels to inset from the end bound
+     * @attr ref android.R.styleable#LayerDrawableItem_end
+     */
+    public int getLayerInsetEnd(int index) {
+        final ChildDrawable childDrawable = mLayerState.mChildren[index];
+        return childDrawable.mInsetE;
+    }
+
     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;
@@ -834,7 +971,6 @@
         }
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         if (mHotspotBounds != null) {
@@ -1230,16 +1366,16 @@
         mMutated = false;
     }
 
-    /** @hide */
     @Override
-    public void setLayoutDirection(int layoutDirection) {
-        super.setLayoutDirection(layoutDirection);
+    public boolean onLayoutDirectionChange(int layoutDirection) {
+        boolean changed = false;
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNum;
         for (int i = 0; i < N; i++) {
-            array[i].mDrawable.setLayoutDirection(layoutDirection);
+            changed |= array[i].mDrawable.setLayoutDirection(layoutDirection);
         }
         updateLayerBounds(getBounds());
+        return changed;
     }
 
     static class ChildDrawable {
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 556c59f..c6ea91d 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -614,7 +614,6 @@
         onHotspotBoundsChanged();
     }
 
-    /** @hide */
     @Override
     public void getHotspotBounds(Rect outRect) {
         outRect.set(mHotspotBounds);
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index e1991fe..595061c 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -29,6 +29,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
+import android.util.MathUtils;
 import android.util.TypedValue;
 import android.util.AttributeSet;
 
@@ -51,12 +52,10 @@
  * @attr ref android.R.styleable#RotateDrawable_pivotY
  * @attr ref android.R.styleable#RotateDrawable_drawable
  */
-public class RotateDrawable extends Drawable implements Drawable.Callback {
-    private static final float MAX_LEVEL = 10000.0f;
+public class RotateDrawable extends DrawableWrapper {
+    private static final int MAX_LEVEL = 10000;
 
-    private final RotateState mState;
-
-    private boolean mMutated;
+    private RotateState mState;
 
     /**
      * Create a new rotating drawable with an empty state.
@@ -65,416 +64,32 @@
         this(null, null);
     }
 
-    /**
-     * Create a new rotating drawable with the specified state. A copy of
-     * this state is used as the internal state for the newly created
-     * drawable.
-     *
-     * @param rotateState the state for this drawable
-     */
-    private RotateDrawable(RotateState rotateState, Resources res) {
-        mState = new RotateState(rotateState, this, res);
-    }
-
-    @Override
-    public void draw(Canvas canvas) {
-        final RotateState st = mState;
-        final Drawable d = st.mDrawable;
-        final Rect bounds = d.getBounds();
-        final int w = bounds.right - bounds.left;
-        final int h = bounds.bottom - bounds.top;
-        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
-        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
-
-        final int saveCount = canvas.save();
-        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
-        d.draw(canvas);
-        canvas.restoreToCount(saveCount);
-    }
-
-    /**
-     * Sets the drawable rotated by this RotateDrawable.
-     *
-     * @param drawable The drawable to rotate
-     */
-    public void setDrawable(Drawable drawable) {
-        final Drawable oldDrawable = mState.mDrawable;
-        if (oldDrawable != drawable) {
-            if (oldDrawable != null) {
-                oldDrawable.setCallback(null);
-            }
-            mState.mDrawable = drawable;
-            if (drawable != null) {
-                drawable.setCallback(this);
-            }
-        }
-    }
-
-    /**
-     * @return The drawable rotated by this RotateDrawable
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
-    }
-
-    @Override
-    public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
-
-    /**
-     * Sets the start angle for rotation.
-     *
-     * @param fromDegrees Starting angle in degrees
-     *
-     * @see #getFromDegrees()
-     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
-     */
-    public void setFromDegrees(float fromDegrees) {
-        if (mState.mFromDegrees != fromDegrees) {
-            mState.mFromDegrees = fromDegrees;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return The starting angle for rotation in degrees
-     *
-     * @see #setFromDegrees(float)
-     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
-     */
-    public float getFromDegrees() {
-        return mState.mFromDegrees;
-    }
-
-    /**
-     * Sets the end angle for rotation.
-     *
-     * @param toDegrees Ending angle in degrees
-     *
-     * @see #getToDegrees()
-     * @attr ref android.R.styleable#RotateDrawable_toDegrees
-     */
-    public void setToDegrees(float toDegrees) {
-        if (mState.mToDegrees != toDegrees) {
-            mState.mToDegrees = toDegrees;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return The ending angle for rotation in degrees
-     *
-     * @see #setToDegrees(float)
-     * @attr ref android.R.styleable#RotateDrawable_toDegrees
-     */
-    public float getToDegrees() {
-        return mState.mToDegrees;
-    }
-
-    /**
-     * Sets the X position around which the drawable is rotated.
-     *
-     * @param pivotX X position around which to rotate. If the X pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            width. Otherwise, the position represents an absolute value in
-     *            pixels.
-     *
-     * @see #setPivotXRelative(boolean)
-     * @attr ref android.R.styleable#RotateDrawable_pivotX
-     */
-    public void setPivotX(float pivotX) {
-        if (mState.mPivotX != pivotX) {
-            mState.mPivotX = pivotX;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return X position around which to rotate
-     *
-     * @see #setPivotX(float)
-     * @attr ref android.R.styleable#RotateDrawable_pivotX
-     */
-    public float getPivotX() {
-        return mState.mPivotX;
-    }
-
-    /**
-     * Sets whether the X pivot value represents a fraction of the drawable
-     * width or an absolute value in pixels.
-     *
-     * @param relative True if the X pivot represents a fraction of the drawable
-     *            width, or false if it represents an absolute value in pixels
-     *
-     * @see #isPivotXRelative()
-     */
-    public void setPivotXRelative(boolean relative) {
-        if (mState.mPivotXRel != relative) {
-            mState.mPivotXRel = relative;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return True if the X pivot represents a fraction of the drawable width,
-     *         or false if it represents an absolute value in pixels
-     *
-     * @see #setPivotXRelative(boolean)
-     */
-    public boolean isPivotXRelative() {
-        return mState.mPivotXRel;
-    }
-
-    /**
-     * Sets the Y position around which the drawable is rotated.
-     *
-     * @param pivotY Y position around which to rotate. If the Y pivot is
-     *            relative, the position represents a fraction of the drawable
-     *            height. Otherwise, the position represents an absolute value
-     *            in pixels.
-     *
-     * @see #getPivotY()
-     * @attr ref android.R.styleable#RotateDrawable_pivotY
-     */
-    public void setPivotY(float pivotY) {
-        if (mState.mPivotY != pivotY) {
-            mState.mPivotY = pivotY;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return Y position around which to rotate
-     *
-     * @see #setPivotY(float)
-     * @attr ref android.R.styleable#RotateDrawable_pivotY
-     */
-    public float getPivotY() {
-        return mState.mPivotY;
-    }
-
-    /**
-     * Sets whether the Y pivot value represents a fraction of the drawable
-     * height or an absolute value in pixels.
-     *
-     * @param relative True if the Y pivot represents a fraction of the drawable
-     *            height, or false if it represents an absolute value in pixels
-     *
-     * @see #isPivotYRelative()
-     */
-    public void setPivotYRelative(boolean relative) {
-        if (mState.mPivotYRel != relative) {
-            mState.mPivotYRel = relative;
-            invalidateSelf();
-        }
-    }
-
-    /**
-     * @return True if the Y pivot represents a fraction of the drawable height,
-     *         or false if it represents an absolute value in pixels
-     *
-     * @see #setPivotYRelative(boolean)
-     */
-    public boolean isPivotYRelative() {
-        return mState.mPivotYRel;
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    @Override
-    public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.invalidateDrawable(this);
-        }
-    }
-
-    @Override
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.scheduleDrawable(this, what, when);
-        }
-    }
-
-    @Override
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-        if (callback != null) {
-            callback.unscheduleDrawable(this, what);
-        }
-    }
-
-   @Override
-    public boolean getPadding(Rect padding) {
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
-
-    @Override
-    protected boolean onStateChange(int[] state) {
-        final boolean changed = mState.mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
-    }
-
-    @Override
-    protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
-        onBoundsChange(getBounds());
-
-        mState.mCurrentDegrees = mState.mFromDegrees +
-                (mState.mToDegrees - mState.mFromDegrees) *
-                        (level / MAX_LEVEL);
-
-        invalidateSelf();
-        return true;
-    }
-
-    @Override
-    protected void onBoundsChange(Rect bounds) {
-        mState.mDrawable.setBounds(bounds.left, bounds.top,
-                bounds.right, bounds.bottom);
-    }
-
-    @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
-    }
-
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
     @Override
     public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
             throws XmlPullParserException, IOException {
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.RotateDrawable);
         super.inflateWithAttributes(r, parser, a, R.styleable.RotateDrawable_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);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
-    @Override
-    public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
-        final RotateState state = mState;
-        if (state == null) {
-            return;
-        }
-
-        if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
-            try {
-                updateStateFromTypedArray(a);
-                verifyRequiredAttributes(a);
-            } catch (XmlPullParserException e) {
-                throw new RuntimeException(e);
-            } finally {
-                a.recycle();
-            }
-        }
-
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
-
-    }
-
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
     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
-                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.RotateDrawable_drawable] == 0)) {
             throw new XmlPullParserException(a.getPositionDescription()
                     + ": <rotate> tag requires a 'drawable' attribute or "
                     + "child tag defining a drawable");
         }
     }
 
-    private void updateStateFromTypedArray(TypedArray a) {
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
         final RotateState state = mState;
 
         // Account for any configuration changes.
@@ -495,72 +110,235 @@
             state.mPivotY = state.mPivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
         }
 
-        state.mFromDegrees = a.getFloat(R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
-        state.mToDegrees = a.getFloat(R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
+        state.mFromDegrees = a.getFloat(
+                R.styleable.RotateDrawable_fromDegrees, state.mFromDegrees);
+        state.mToDegrees = a.getFloat(
+                R.styleable.RotateDrawable_toDegrees, state.mToDegrees);
         state.mCurrentDegrees = state.mFromDegrees;
 
         final Drawable dr = a.getDrawable(R.styleable.RotateDrawable_drawable);
         if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
+            setDrawable(dr);
         }
     }
 
     @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
+    public void applyTheme(Theme t) {
+        final RotateState state = mState;
+        if (state == null) {
+            return;
         }
-        return this;
+
+        if (state.mThemeAttrs != null) {
+            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.RotateDrawable);
+            try {
+                updateStateFromTypedArray(a);
+                verifyRequiredAttributes(a);
+            } catch (XmlPullParserException e) {
+                throw new RuntimeException(e);
+            } finally {
+                a.recycle();
+            }
+        }
+
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final Drawable d = getDrawable();
+        final Rect bounds = d.getBounds();
+        final int w = bounds.right - bounds.left;
+        final int h = bounds.bottom - bounds.top;
+        final RotateState st = mState;
+        final float px = st.mPivotXRel ? (w * st.mPivotX) : st.mPivotX;
+        final float py = st.mPivotYRel ? (h * st.mPivotY) : st.mPivotY;
+
+        final int saveCount = canvas.save();
+        canvas.rotate(st.mCurrentDegrees, px + bounds.left, py + bounds.top);
+        d.draw(canvas);
+        canvas.restoreToCount(saveCount);
     }
 
     /**
-     * @hide
+     * Sets the start angle for rotation.
+     *
+     * @param fromDegrees starting angle in degrees
+     * @see #getFromDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
+    public void setFromDegrees(float fromDegrees) {
+        if (mState.mFromDegrees != fromDegrees) {
+            mState.mFromDegrees = fromDegrees;
+            invalidateSelf();
+        }
     }
 
     /**
-     * Represents the state of a rotation for a given drawable. The same
-     * rotate drawable can be invoked with different states to drive several
-     * rotations at the same time.
+     * @return starting angle for rotation in degrees
+     * @see #setFromDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_fromDegrees
      */
-    final static class RotateState extends Drawable.ConstantState {
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
+    public float getFromDegrees() {
+        return mState.mFromDegrees;
+    }
 
-        Drawable mDrawable;
+    /**
+     * Sets the end angle for rotation.
+     *
+     * @param toDegrees ending angle in degrees
+     * @see #getToDegrees()
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
+     */
+    public void setToDegrees(float toDegrees) {
+        if (mState.mToDegrees != toDegrees) {
+            mState.mToDegrees = toDegrees;
+            invalidateSelf();
+        }
+    }
 
+    /**
+     * @return ending angle for rotation in degrees
+     * @see #setToDegrees(float)
+     * @attr ref android.R.styleable#RotateDrawable_toDegrees
+     */
+    public float getToDegrees() {
+        return mState.mToDegrees;
+    }
+
+    /**
+     * Sets the X position around which the drawable is rotated.
+     *
+     * @param pivotX X position around which to rotate. If the X pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            width. Otherwise, the position represents an absolute value in
+     *            pixels.
+     * @see #setPivotXRelative(boolean)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
+     */
+    public void setPivotX(float pivotX) {
+        if (mState.mPivotX != pivotX) {
+            mState.mPivotX = pivotX;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return X position around which to rotate
+     * @see #setPivotX(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotX
+     */
+    public float getPivotX() {
+        return mState.mPivotX;
+    }
+
+    /**
+     * Sets whether the X pivot value represents a fraction of the drawable
+     * width or an absolute value in pixels.
+     *
+     * @param relative true if the X pivot represents a fraction of the drawable
+     *            width, or false if it represents an absolute value in pixels
+     * @see #isPivotXRelative()
+     */
+    public void setPivotXRelative(boolean relative) {
+        if (mState.mPivotXRel != relative) {
+            mState.mPivotXRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return true if the X pivot represents a fraction of the drawable width,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotXRelative(boolean)
+     */
+    public boolean isPivotXRelative() {
+        return mState.mPivotXRel;
+    }
+
+    /**
+     * Sets the Y position around which the drawable is rotated.
+     *
+     * @param pivotY Y position around which to rotate. If the Y pivot is
+     *            relative, the position represents a fraction of the drawable
+     *            height. Otherwise, the position represents an absolute value
+     *            in pixels.
+     * @see #getPivotY()
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
+     */
+    public void setPivotY(float pivotY) {
+        if (mState.mPivotY != pivotY) {
+            mState.mPivotY = pivotY;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return Y position around which to rotate
+     * @see #setPivotY(float)
+     * @attr ref android.R.styleable#RotateDrawable_pivotY
+     */
+    public float getPivotY() {
+        return mState.mPivotY;
+    }
+
+    /**
+     * Sets whether the Y pivot value represents a fraction of the drawable
+     * height or an absolute value in pixels.
+     *
+     * @param relative True if the Y pivot represents a fraction of the drawable
+     *            height, or false if it represents an absolute value in pixels
+     * @see #isPivotYRelative()
+     */
+    public void setPivotYRelative(boolean relative) {
+        if (mState.mPivotYRel != relative) {
+            mState.mPivotYRel = relative;
+            invalidateSelf();
+        }
+    }
+
+    /**
+     * @return true if the Y pivot represents a fraction of the drawable height,
+     *         or false if it represents an absolute value in pixels
+     * @see #setPivotYRelative(boolean)
+     */
+    public boolean isPivotYRelative() {
+        return mState.mPivotYRel;
+    }
+
+    @Override
+    protected boolean onLevelChange(int level) {
+        super.onLevelChange(level);
+
+        final float value = level / (float) MAX_LEVEL;
+        final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
+        mState.mCurrentDegrees = degrees;
+
+        invalidateSelf();
+        return true;
+    }
+
+    @Override
+    DrawableWrapperState mutateConstantState() {
+        mState = new RotateState(mState);
+        return mState;
+    }
+
+    static final class RotateState extends DrawableWrapper.DrawableWrapperState {
         boolean mPivotXRel = true;
         float mPivotX = 0.5f;
         boolean mPivotYRel = true;
         float mPivotY = 0.5f;
-
         float mFromDegrees = 0.0f;
         float mToDegrees = 360.0f;
-
         float mCurrentDegrees = 0.0f;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        RotateState(RotateState orig) {
+            super(orig);
 
-        RotateState(RotateState orig, RotateDrawable owner, Resources res) {
             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());
                 mPivotXRel = orig.mPivotXRel;
                 mPivotX = orig.mPivotX;
                 mPivotYRel = orig.mPivotYRel;
@@ -568,38 +346,18 @@
                 mFromDegrees = orig.mFromDegrees;
                 mToDegrees = orig.mToDegrees;
                 mCurrentDegrees = orig.mCurrentDegrees;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new RotateDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new RotateDrawable(this, res);
         }
+    }
 
-        @Override
-        public int getChangingConfigurations() {
-            return mChangingConfigurations;
-        }
+    private RotateDrawable(RotateState state, Resources res) {
+        super(state, res);
 
-        public boolean canConstantState() {
-            if (!mCheckedConstantState) {
-                mCanConstantState = mDrawable.getConstantState() != null;
-                mCheckedConstantState = true;
-            }
-
-            return mCanConstantState;
-        }
+        mState = state;
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index da722f3..0acbeda 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -21,17 +21,17 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.content.res.ColorStateList;
 import android.content.res.Resources;
-import android.content.res.TypedArray;
 import android.content.res.Resources.Theme;
-import android.graphics.*;
-import android.graphics.PorterDuff.Mode;
-import android.view.Gravity;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Gravity;
 
 import java.io.IOException;
-import java.util.Collection;
 
 /**
  * A Drawable that changes the size of another Drawable based on its current
@@ -49,44 +49,37 @@
  * @attr ref android.R.styleable#ScaleDrawable_scaleGravity
  * @attr ref android.R.styleable#ScaleDrawable_drawable
  */
-public class ScaleDrawable extends Drawable implements Drawable.Callback {
-    private ScaleState mState;
-    private boolean mMutated;
+public class ScaleDrawable extends DrawableWrapper {
+    private static final int MAX_LEVEL = 10000;
+
     private final Rect mTmpRect = new Rect();
 
+    private ScaleState mState;
+
     ScaleDrawable() {
-        this(null, null);
+        this(new ScaleState(null), null);
     }
 
+    /**
+     * Creates a new scale drawable with the specified gravity and scale
+     * properties.
+     *
+     * @param drawable the drawable to scale
+     * @param gravity gravity constant (see {@link Gravity} used to position
+     *                the scaled drawable within the parent container
+     * @param scaleWidth width scaling factor [0...1] to use then the level is
+     *                   at the maximum value, or -1 to not scale width
+     * @param scaleHeight height scaling factor [0...1] to use then the level
+     *                    is at the maximum value, or -1 to not scale height
+     */
     public ScaleDrawable(Drawable drawable, int gravity, float scaleWidth, float scaleHeight) {
-        this(null, null);
+        this(new ScaleState(null), null);
 
-        mState.mDrawable = drawable;
         mState.mGravity = gravity;
         mState.mScaleWidth = scaleWidth;
         mState.mScaleHeight = scaleHeight;
 
-        if (drawable != null) {
-            drawable.setCallback(this);
-        }
-    }
-
-    /**
-     * Returns the drawable scaled by this ScaleDrawable.
-     */
-    public Drawable getDrawable() {
-        return mState.mDrawable;
-    }
-
-    private static float getPercent(TypedArray a, int name, float defaultValue) {
-        final String s = a.getString(name);
-        if (s != null) {
-            if (s.endsWith("%")) {
-                String f = s.substring(0, s.length() - 1);
-                return Float.parseFloat(f) / 100.0f;
-            }
-        }
-        return defaultValue;
+        setDrawable(drawable);
     }
 
     @Override
@@ -95,28 +88,70 @@
         super.inflate(r, parser, attrs, theme);
 
         final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ScaleDrawable);
-
-        // 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);
+        inflateChildDrawable(r, parser, attrs, theme);
         verifyRequiredAttributes(a);
         a.recycle();
     }
 
+    private void verifyRequiredAttributes(TypedArray a) throws XmlPullParserException {
+        // If we're not waiting on a theme, verify required attributes.
+        if (getDrawable() == null && (mState.mThemeAttrs == null
+                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + ": <scale> tag requires a 'drawable' attribute or "
+                    + "child tag defining a drawable");
+        }
+    }
+
+    @Override
+    void updateStateFromTypedArray(TypedArray a) {
+        super.updateStateFromTypedArray(a);
+
+        final ScaleState state = mState;
+        state.mScaleWidth = getPercent(a,
+                R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
+        state.mScaleHeight = getPercent(a,
+                R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
+        state.mGravity = a.getInt(
+                R.styleable.ScaleDrawable_scaleGravity, state.mGravity);
+        state.mUseIntrinsicSizeAsMin = a.getBoolean(
+                R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
+
+        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
+        if (dr != null) {
+            setDrawable(dr);
+        }
+    }
+
+    private static float getPercent(TypedArray a, int index, float defaultValue) {
+        final int type = a.getType(index);
+        if (type == TypedValue.TYPE_FRACTION || type == TypedValue.TYPE_NULL) {
+            return a.getFraction(index, 1, 1, defaultValue);
+        }
+
+        // Coerce to float.
+        final String s = a.getString(index);
+        if (s != null) {
+            if (s.endsWith("%")) {
+                final String f = s.substring(0, s.length() - 1);
+                return Float.parseFloat(f) / 100.0f;
+            }
+        }
+
+        return defaultValue;
+    }
+
     @Override
     public void applyTheme(Theme t) {
-        super.applyTheme(t);
-
         final ScaleState state = mState;
         if (state == null) {
             return;
         }
 
         if (state.mThemeAttrs != null) {
-            final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ScaleDrawable);
+            final TypedArray a = t.resolveAttributes(
+                    state.mThemeAttrs, R.styleable.ScaleDrawable);
             try {
                 updateStateFromTypedArray(a);
                 verifyRequiredAttributes(a);
@@ -127,161 +162,37 @@
             }
         }
 
-        if (state.mDrawable != null && state.mDrawable.canApplyTheme()) {
-            state.mDrawable.applyTheme(t);
-        }
+        // The drawable may have changed as a result of applying the theme, so
+        // apply the theme to the wrapped drawable last.
+        super.applyTheme(t);
     }
 
-    private void inflateChildElements(Resources r, XmlPullParser parser, AttributeSet attrs,
-            Theme theme) throws XmlPullParserException, IOException {
-        Drawable dr = null;
-        int type;
-        final int outerDepth = parser.getDepth();
-        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
-                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
-            if (type != XmlPullParser.START_TAG) {
-                continue;
-            }
-            dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
-        }
-
-        if (dr != null) {
-            mState.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
-    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
-                || mState.mThemeAttrs[R.styleable.ScaleDrawable_drawable] == 0)) {
-            throw new XmlPullParserException(a.getPositionDescription()
-                    + ": <scale> tag requires a 'drawable' attribute or "
-                    + "child tag defining a drawable");
-        }
-    }
-
-    private void updateStateFromTypedArray(TypedArray a) {
-        final ScaleState state = mState;
-
-        // Account for any configuration changes.
-        state.mChangingConfigurations |= a.getChangingConfigurations();
-
-        // Extract the theme attributes, if any.
-        state.mThemeAttrs = a.extractThemeAttrs();
-
-        state.mScaleWidth = getPercent(
-                a, R.styleable.ScaleDrawable_scaleWidth, state.mScaleWidth);
-        state.mScaleHeight = getPercent(
-                a, R.styleable.ScaleDrawable_scaleHeight, state.mScaleHeight);
-        state.mGravity = a.getInt(R.styleable.ScaleDrawable_scaleGravity, state.mGravity);
-        state.mUseIntrinsicSizeAsMin = a.getBoolean(
-                R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, state.mUseIntrinsicSizeAsMin);
-
-        final Drawable dr = a.getDrawable(R.styleable.ScaleDrawable_drawable);
-        if (dr != null) {
-            state.mDrawable = dr;
-            dr.setCallback(this);
-        }
-    }
-
-    @Override
-    public boolean canApplyTheme() {
-        return (mState != null && mState.canApplyTheme()) || super.canApplyTheme();
-    }
-
-    // overrides from Drawable.Callback
-
-    public void invalidateDrawable(Drawable who) {
-        if (getCallback() != null) {
-            getCallback().invalidateDrawable(this);
-        }
-    }
-
-    public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        if (getCallback() != null) {
-            getCallback().scheduleDrawable(this, what, when);
-        }
-    }
-
-    public void unscheduleDrawable(Drawable who, Runnable what) {
-        if (getCallback() != null) {
-            getCallback().unscheduleDrawable(this, what);
-        }
-    }
-
-    // overrides from Drawable
-
     @Override
     public void draw(Canvas canvas) {
-        if (mState.mDrawable.getLevel() != 0)
-            mState.mDrawable.draw(canvas);
-    }
-
-    @Override
-    public int getChangingConfigurations() {
-        return super.getChangingConfigurations()
-                | mState.mChangingConfigurations
-                | mState.mDrawable.getChangingConfigurations();
-    }
-
-    @Override
-    public boolean getPadding(Rect padding) {
-        // XXX need to adjust padding!
-        return mState.mDrawable.getPadding(padding);
-    }
-
-    @Override
-    public boolean setVisible(boolean visible, boolean restart) {
-        mState.mDrawable.setVisible(visible, restart);
-        return super.setVisible(visible, restart);
-    }
-
-    @Override
-    public void setAlpha(int alpha) {
-        mState.mDrawable.setAlpha(alpha);
-    }
-
-    @Override
-    public int getAlpha() {
-        return mState.mDrawable.getAlpha();
-    }
-
-    @Override
-    public void setColorFilter(ColorFilter cf) {
-        mState.mDrawable.setColorFilter(cf);
-    }
-
-    @Override
-    public void setTintList(ColorStateList tint) {
-        mState.mDrawable.setTintList(tint);
-    }
-
-    @Override
-    public void setTintMode(Mode tintMode) {
-        mState.mDrawable.setTintMode(tintMode);
+        final Drawable d = getDrawable();
+        if (d != null && d.getLevel() != 0) {
+            d.draw(canvas);
+        }
     }
 
     @Override
     public int getOpacity() {
-        return mState.mDrawable.getOpacity();
-    }
+        final Drawable d = getDrawable();
+        if (d.getLevel() == 0) {
+            return PixelFormat.TRANSPARENT;
+        }
 
-    @Override
-    public boolean isStateful() {
-        return mState.mDrawable.isStateful();
-    }
+        final int opacity = d.getOpacity();
+        if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) {
+            return PixelFormat.TRANSLUCENT;
+        }
 
-    @Override
-    protected boolean onStateChange(int[] state) {
-        boolean changed = mState.mDrawable.setState(state);
-        onBoundsChange(getBounds());
-        return changed;
+        return opacity;
     }
 
     @Override
     protected boolean onLevelChange(int level) {
-        mState.mDrawable.setLevel(level);
+        super.onLevelChange(level);
         onBoundsChange(getBounds());
         invalidateSelf();
         return true;
@@ -289,144 +200,67 @@
 
     @Override
     protected void onBoundsChange(Rect bounds) {
+        final Drawable d = getDrawable();
         final Rect r = mTmpRect;
         final boolean min = mState.mUseIntrinsicSizeAsMin;
-        int level = getLevel();
+        final int level = getLevel();
+
         int w = bounds.width();
         if (mState.mScaleWidth > 0) {
-            final int iw = min ? mState.mDrawable.getIntrinsicWidth() : 0;
-            w -= (int) ((w - iw) * (10000 - level) * mState.mScaleWidth / 10000);
+            final int iw = min ? d.getIntrinsicWidth() : 0;
+            w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
         }
+
         int h = bounds.height();
         if (mState.mScaleHeight > 0) {
-            final int ih = min ? mState.mDrawable.getIntrinsicHeight() : 0;
-            h -= (int) ((h - ih) * (10000 - level) * mState.mScaleHeight / 10000);
+            final int ih = min ? d.getIntrinsicHeight() : 0;
+            h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
         }
+
         final int layoutDirection = getLayoutDirection();
         Gravity.apply(mState.mGravity, w, h, bounds, r, layoutDirection);
 
         if (w > 0 && h > 0) {
-            mState.mDrawable.setBounds(r.left, r.top, r.right, r.bottom);
+            d.setBounds(r.left, r.top, r.right, r.bottom);
         }
     }
 
     @Override
-    public int getIntrinsicWidth() {
-        return mState.mDrawable.getIntrinsicWidth();
+    DrawableWrapperState mutateConstantState() {
+        mState = new ScaleState(mState);
+        return mState;
     }
 
-    @Override
-    public int getIntrinsicHeight() {
-        return mState.mDrawable.getIntrinsicHeight();
-    }
-
-    @Override
-    public ConstantState getConstantState() {
-        if (mState.canConstantState()) {
-            mState.mChangingConfigurations = getChangingConfigurations();
-            return mState;
-        }
-        return null;
-    }
-
-    @Override
-    public Drawable mutate() {
-        if (!mMutated && super.mutate() == this) {
-            mState.mDrawable.mutate();
-            mMutated = true;
-        }
-        return this;
-    }
-
-    /**
-     * @hide
-     */
-    public void clearMutated() {
-        super.clearMutated();
-        mState.mDrawable.clearMutated();
-        mMutated = false;
-    }
-
-    final static class ScaleState extends ConstantState {
+    static final class ScaleState extends DrawableWrapper.DrawableWrapperState {
         /** Constant used to disable scaling for a particular dimension. */
         private static final float DO_NOT_SCALE = -1.0f;
 
-        int[] mThemeAttrs;
-        int mChangingConfigurations;
-
-        Drawable mDrawable;
-
         float mScaleWidth = DO_NOT_SCALE;
         float mScaleHeight = DO_NOT_SCALE;
         int mGravity = Gravity.LEFT;
         boolean mUseIntrinsicSizeAsMin = false;
 
-        private boolean mCheckedConstantState;
-        private boolean mCanConstantState;
+        ScaleState(ScaleState orig) {
+            super(orig);
 
-        ScaleState(ScaleState orig, ScaleDrawable owner, Resources res) {
             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());
                 mScaleWidth = orig.mScaleWidth;
                 mScaleHeight = orig.mScaleHeight;
                 mGravity = orig.mGravity;
                 mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin;
-                mCheckedConstantState = mCanConstantState = true;
             }
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null || (mDrawable != null && mDrawable.canApplyTheme())
-                    || super.canApplyTheme();
-        }
-
-        @Override
-        public Drawable newDrawable() {
-            return new ScaleDrawable(this, null);
-        }
-
-        @Override
         public Drawable newDrawable(Resources res) {
             return new ScaleDrawable(this, res);
         }
-
-        @Override
-        public int getChangingConfigurations() {
-            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;
-        }
     }
 
     private ScaleDrawable(ScaleState state, Resources res) {
-        mState = new ScaleState(state, this, res);
+        super(state, res);
+
+        mState = state;
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index 59d0ba6..c83af11 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -309,16 +309,6 @@
         mMutated = false;
     }
 
-    /** @hide */
-    @Override
-    public void setLayoutDirection(int layoutDirection) {
-        super.setLayoutDirection(layoutDirection);
-
-        // Let the container handle setting its own layout direction. Otherwise,
-        // we're accessing potentially unused states.
-        mStateListState.setLayoutDirection(layoutDirection);
-    }
-
     static class StateListState extends DrawableContainerState {
         int[] mThemeAttrs;
         int[][] mStateSets;
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index e753a7c..bfbf028 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -18,8 +18,14 @@
 
 import com.android.org.conscrypt.NativeCrypto;
 
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.OperationResult;
 import android.util.Log;
 
 import java.util.Locale;
@@ -58,6 +64,8 @@
 
     private final IKeystoreService mBinder;
 
+    private IBinder mToken;
+
     private KeyStore(IKeystoreService binder) {
         mBinder = binder;
     }
@@ -68,6 +76,13 @@
         return new KeyStore(keystore);
     }
 
+    private synchronized IBinder getToken() {
+        if (mToken == null) {
+            mToken = new Binder();
+        }
+        return mToken;
+    }
+
     static int getKeyTypeForAlgorithm(String keyType) {
         if ("RSA".equalsIgnoreCase(keyType)) {
             return NativeCrypto.EVP_PKEY_RSA;
@@ -363,4 +378,100 @@
     public int getLastError() {
         return mError;
     }
+
+    public boolean addRngEntropy(byte[] data) {
+        try {
+            return mBinder.addRngEntropy(data) == NO_ERROR;
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return false;
+        }
+    }
+
+    public int generateKey(String alias, KeymasterArguments args, int uid, int flags,
+            KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.generateKey(alias, args, uid, flags, outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int generateKey(String alias, KeymasterArguments args, int flags,
+            KeyCharacteristics outCharacteristics) {
+        return generateKey(alias, args, UID_SELF, flags, outCharacteristics);
+    }
+
+    public int getKeyCharacteristics(String alias, byte[] clientId, byte[] appId,
+            KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.getKeyCharacteristics(alias, clientId, appId, outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
+            int uid, int flags, KeyCharacteristics outCharacteristics) {
+        try {
+            return mBinder.importKey(alias, args, format, keyData, uid, flags,
+                    outCharacteristics);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
+
+    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
+            int flags, KeyCharacteristics outCharacteristics) {
+        return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
+    }
+
+    public ExportResult exportKey(String alias, int format, byte[] clientId, byte[] appId) {
+        try {
+            return mBinder.exportKey(alias, format, clientId, appId);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult begin(String alias, int purpose, boolean pruneable,
+            KeymasterArguments args, KeymasterArguments outArgs) {
+        try {
+            return mBinder.begin(getToken(), alias, purpose, pruneable, args, outArgs);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
+        try {
+            return mBinder.update(token, arguments, input);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
+        try {
+            return mBinder.finish(token, arguments, signature);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return null;
+        }
+    }
+
+    public int abort(IBinder token) {
+        try {
+            return mBinder.abort(token);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Cannot connect to keystore", e);
+            return SYSTEM_ERROR;
+        }
+    }
 }
diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp
index 4b3382e..782806e 100644
--- a/libs/androidfw/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -532,7 +532,7 @@
 void _FileAsset::close(void)
 {
     if (mMap != NULL) {
-        mMap->release();
+        delete mMap;
         mMap = NULL;
     }
     if (mBuf != NULL) {
@@ -612,7 +612,7 @@
 
         map = new FileMap;
         if (!map->create(NULL, fileno(mFp), mStart, mLength, true)) {
-            map->release();
+            delete map;
             return NULL;
         }
 
@@ -827,7 +827,7 @@
 void _CompressedAsset::close(void)
 {
     if (mMap != NULL) {
-        mMap->release();
+        delete mMap;
         mMap = NULL;
     }
 
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index ef0d072..af3d9b3 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -200,7 +200,7 @@
 
     FileMap* newMap = new FileMap();
     if (!newMap->create(mFileName, fd, ze.offset, actualLen, true)) {
-        newMap->release();
+        delete newMap;
         return NULL;
     }
 
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index e05dd55..5dacbb5 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -43,11 +43,13 @@
     Extensions.cpp \
     FboCache.cpp \
     FontRenderer.cpp \
+    FrameInfo.cpp \
     GammaFontRenderer.cpp \
     GlopBuilder.cpp \
     GradientCache.cpp \
     Image.cpp \
     Interpolator.cpp \
+    JankTracker.cpp \
     Layer.cpp \
     LayerCache.cpp \
     LayerRenderer.cpp \
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f4fc068..bd933b8 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -263,7 +263,7 @@
             const Layer* layer = *it;
             log.appendFormat("    Layer size %dx%d; isTextureLayer()=%d; texid=%u fbo=%u; refs=%d\n",
                     layer->getWidth(), layer->getHeight(),
-                    layer->isTextureLayer(), layer->getTexture(),
+                    layer->isTextureLayer(), layer->getTextureId(),
                     layer->getFbo(), layer->getStrongCount());
             memused += layer->getWidth() * layer->getHeight() * 4;
         }
@@ -405,7 +405,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void Caches::initTempProperties() {
-    propertyLightDiameter = -1.0f;
+    propertyLightRadius = -1.0f;
     propertyLightPosY = -1.0f;
     propertyLightPosZ = -1.0f;
     propertyAmbientRatio = -1.0f;
@@ -419,9 +419,9 @@
         propertyAmbientRatio = fmin(fmax(atof(value), 0.0), 10.0);
         ALOGD("ambientRatio = %.2f", propertyAmbientRatio);
         return;
-    } else if (!strcmp(name, "lightDiameter")) {
-        propertyLightDiameter = fmin(fmax(atof(value), 0.0), 3000.0);
-        ALOGD("lightDiameter = %.2f", propertyLightDiameter);
+    } else if (!strcmp(name, "lightRadius")) {
+        propertyLightRadius = fmin(fmax(atof(value), 0.0), 3000.0);
+        ALOGD("lightRadius = %.2f", propertyLightRadius);
         return;
     } else if (!strcmp(name, "lightPosY")) {
         propertyLightPosY = fmin(fmax(atof(value), 0.0), 3000.0);
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 18bb5e6..92a87e2 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -214,7 +214,7 @@
     void initTempProperties();
     void setTempProperty(const char* name, const char* value);
 
-    float propertyLightDiameter;
+    float propertyLightRadius;
     float propertyLightPosY;
     float propertyLightPosZ;
     float propertyAmbientRatio;
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 0792120..6a59a13 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -62,7 +62,7 @@
     if (mSurfaceTexture.get()) {
         if (mNeedsGLContextAttach) {
             mNeedsGLContextAttach = false;
-            mSurfaceTexture->attachToContext(mLayer->getTexture());
+            mSurfaceTexture->attachToContext(mLayer->getTextureId());
         }
         if (mUpdateTexImage) {
             mUpdateTexImage = false;
diff --git a/core/java/android/midi/IMidiDeviceServer.aidl b/libs/hwui/FrameInfo.cpp
similarity index 63%
copy from core/java/android/midi/IMidiDeviceServer.aidl
copy to libs/hwui/FrameInfo.cpp
index 31fdbbb..6da1fa8 100644
--- a/core/java/android/midi/IMidiDeviceServer.aidl
+++ b/libs/hwui/FrameInfo.cpp
@@ -1,5 +1,5 @@
 /*
- * 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.
@@ -13,14 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#include "FrameInfo.h"
 
-package android.midi;
+#include <cstring>
 
-import android.os.ParcelFileDescriptor;
+namespace android {
+namespace uirenderer {
 
-/** @hide */
-interface IMidiDeviceServer
-{
-    ParcelFileDescriptor openInputPort(int portNumber);
-    ParcelFileDescriptor openOutputPort(int portNumber);
+void FrameInfo::importUiThreadInfo(int64_t* info) {
+    memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
 }
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
new file mode 100644
index 0000000..65daf03
--- /dev/null
+++ b/libs/hwui/FrameInfo.h
@@ -0,0 +1,125 @@
+/*
+ * 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 FRAMEINFO_H_
+#define FRAMEINFO_H_
+
+#include "utils/Macros.h"
+
+#include <cutils/compiler.h>
+#include <utils/Timers.h>
+
+#include <memory.h>
+
+namespace android {
+namespace uirenderer {
+
+#define UI_THREAD_FRAME_INFO_SIZE 9
+
+enum class FrameInfoIndex {
+    kFlags = 0,
+    kIntendedVsync,
+    kVsync,
+    kOldestInputEvent,
+    kNewestInputEvent,
+    kHandleInputStart,
+    kAnimationStart,
+    kPerformTraversalsStart,
+    kDrawStart,
+    // End of UI frame info
+
+    kSyncStart,
+    kIssueDrawCommandsStart,
+    kSwapBuffers,
+    kFrameCompleted,
+
+    // Must be the last value!
+    kNumIndexes
+};
+
+enum class FrameInfoFlags {
+    kWindowLayoutChanged = 1 << 0,
+    kRTAnimation = 1 << 1,
+    kSurfaceCanvas = 1 << 2,
+};
+MAKE_FLAGS_ENUM(FrameInfoFlags)
+
+class ANDROID_API UiFrameInfoBuilder {
+public:
+    UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
+        memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+    }
+
+    UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) {
+        set(FrameInfoIndex::kVsync) = vsyncTime;
+        set(FrameInfoIndex::kIntendedVsync) = intendedVsync;
+        return *this;
+    }
+
+    UiFrameInfoBuilder& addFlag(FrameInfoFlags flag) {
+        set(FrameInfoIndex::kFlags) |= static_cast<uint64_t>(flag);
+        return *this;
+    }
+
+private:
+    inline int64_t& set(FrameInfoIndex index) {
+        return mBuffer[static_cast<int>(index)];
+    }
+
+    int64_t* mBuffer;
+};
+
+class FrameInfo {
+public:
+    void importUiThreadInfo(int64_t* info);
+
+    void markSyncStart() {
+        set(FrameInfoIndex::kSyncStart) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markIssueDrawCommandsStart() {
+        set(FrameInfoIndex::kIssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markSwapBuffers() {
+        set(FrameInfoIndex::kSwapBuffers) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markFrameCompleted() {
+        set(FrameInfoIndex::kFrameCompleted) = systemTime(CLOCK_MONOTONIC);
+    }
+
+    int64_t operator[](FrameInfoIndex index) const {
+        if (index == FrameInfoIndex::kNumIndexes) return 0;
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+    int64_t operator[](int index) const {
+        if (index < 0 || index >= static_cast<int>(FrameInfoIndex::kNumIndexes)) return 0;
+        return mFrameInfo[index];
+    }
+
+private:
+    inline int64_t& set(FrameInfoIndex index) {
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+    int64_t mFrameInfo[static_cast<int>(FrameInfoIndex::kNumIndexes)];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FRAMEINFO_H_ */
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 6eca468..e500546 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -76,18 +76,20 @@
         GLuint indexBufferObject;
         const void* vertices;
         const void* indices;
+        GLvoid* texCoordOffset;
         int elementCount;
         GLsizei stride;
-        GLvoid* texCoordOffset;
         TextureVertex mappedVertices[4];
     } mesh;
 
     struct Fill {
         Program* program;
 
-        Texture* texture;
-        GLenum textureFilter;
-        GLenum textureClamp;
+        struct TextureData {
+            Texture* texture;
+            GLenum filter;
+            GLenum clamp;
+        } texture;
 
         bool colorEnabled;
         FloatColor color;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index f133d42..4617588 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -73,8 +73,7 @@
     return *this;
 }
 
-GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper,
-        bool isAlphaMaskTexture) {
+GlopBuilder& GlopBuilder::setMeshTexturedUnitQuad(const UvMapper* uvMapper) {
     TRIGGER_STAGE(kMeshStage);
 
     mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
@@ -87,19 +86,18 @@
 
         mOutGlop->mesh.vertexBufferObject = 0;
         mOutGlop->mesh.vertices = &mOutGlop->mesh.mappedVertices[0];
+        mOutGlop->mesh.texCoordOffset = &mOutGlop->mesh.mappedVertices[0].u;
     } else {
         // standard UV coordinates, use regular unit quad VBO
         mOutGlop->mesh.vertexBufferObject = mRenderState.meshState().getUnitQuadVBO();
         mOutGlop->mesh.vertices = nullptr;
+        mOutGlop->mesh.texCoordOffset = (GLvoid*) kMeshTextureOffset;
     }
     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;
 }
 
@@ -112,13 +110,29 @@
     mOutGlop->mesh.vertices = vertexData;
     mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
     mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.texCoordOffset = nullptr;
     mOutGlop->mesh.elementCount = 6 * quadCount;
     mOutGlop->mesh.stride = kVertexStride;
-    mOutGlop->mesh.texCoordOffset = nullptr;
 
     return *this;
 }
 
+GlopBuilder& GlopBuilder::setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount) {
+    TRIGGER_STAGE(kMeshStage);
+
+    mOutGlop->mesh.vertexFlags = kTextureCoord_Attrib;
+    mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
+    mOutGlop->mesh.vertexBufferObject = 0;
+    mOutGlop->mesh.vertices = &vertexData[0].x;
+    mOutGlop->mesh.indexBufferObject = mRenderState.meshState().getQuadListIBO();
+    mOutGlop->mesh.indices = nullptr;
+    mOutGlop->mesh.texCoordOffset = &vertexData[0].u;
+    mOutGlop->mesh.elementCount = elementCount;
+    mOutGlop->mesh.stride = kTextureVertexStride;
+    mDescription.hasTexture = true;
+    return *this;
+}
+
 GlopBuilder& GlopBuilder::setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp) {
     TRIGGER_STAGE(kMeshStage);
 
@@ -132,6 +146,7 @@
     mOutGlop->mesh.vertices = vertexBuffer.getBuffer();
     mOutGlop->mesh.indexBufferObject = 0;
     mOutGlop->mesh.indices = vertexBuffer.getIndices();
+    mOutGlop->mesh.texCoordOffset = nullptr;
     mOutGlop->mesh.elementCount = indices
             ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
     mOutGlop->mesh.stride = alphaVertex ? kAlphaVertexStride : kVertexStride;
@@ -168,7 +183,7 @@
     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->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
             || mOutGlop->roundRectClipState
             || PaintUtils::isBlendedShader(shader)
             || PaintUtils::isBlendedColorFilter(colorFilter)
@@ -240,9 +255,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = &texture;
-    mOutGlop->fill.textureFilter = PaintUtils::getFilter(paint);
-    mOutGlop->fill.textureClamp = GL_CLAMP_TO_EDGE;
+    mOutGlop->fill.texture = { &texture, PaintUtils::getFilter(paint), GL_CLAMP_TO_EDGE };
 
     if (paint) {
         int color = paint->getColor();
@@ -270,6 +283,7 @@
         }
     }
 
+    mDescription.hasAlpha8Texture = isAlphaMaskTexture;
     if (isAlphaMaskTexture) {
         mDescription.modulate = mOutGlop->fill.color.isNotBlack();
     } else {
@@ -282,9 +296,7 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = nullptr;
-    mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
-    mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
@@ -297,15 +309,13 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = &texture;
-
-    //specify invalid, since these are always static for PathTextures
-    mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
-    mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
+    //specify invalid filter/clamp, since these are always static for PathTextures
+    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
 
     setFill(paint.getColor(), alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
 
+    mDescription.hasAlpha8Texture = true;
     mDescription.modulate = mOutGlop->fill.color.isNotBlack();
     return *this;
 }
@@ -315,11 +325,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = &texture;
-
-    //specify invalid, since these are always static for ShadowTextures
-    mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
-    mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
+    //specify invalid filter/clamp, since these are always static for ShadowTextures
+    mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM };
 
     const int ALPHA_BITMASK = SK_ColorBLACK;
     const int COLOR_BITMASK = ~ALPHA_BITMASK;
@@ -331,6 +338,7 @@
     setFill(shadowColor, alphaScale, PaintUtils::getXfermode(paint.getXfermode()),
             paint.getShader(), paint.getColorFilter());
 
+    mDescription.hasAlpha8Texture = true;
     mDescription.modulate = mOutGlop->fill.color.isNotBlack();
     return *this;
 }
@@ -339,12 +347,8 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = nullptr;
-    mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
-    mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
-
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kSrcOver_Mode, nullptr, nullptr);
-
     return *this;
 }
 
@@ -352,19 +356,30 @@
     TRIGGER_STAGE(kFillStage);
     REQUIRE_STAGES(kMeshStage);
 
-    mOutGlop->fill.texture = nullptr;
-    mOutGlop->fill.textureFilter = GL_INVALID_ENUM;
-    mOutGlop->fill.textureClamp = GL_INVALID_ENUM;
-
+    mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM };
     setFill(SK_ColorBLACK, 1.0f, SkXfermode::kClear_Mode, nullptr, nullptr);
-
     return *this;
 }
+
+GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
+        float alpha, SkXfermode::Mode mode) {
+    TRIGGER_STAGE(kFillStage);
+    REQUIRE_STAGES(kMeshStage);
+
+    mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE };
+    mOutGlop->fill.color = { alpha, alpha, alpha, alpha };
+
+    setFill(SK_ColorWHITE, alpha, mode, nullptr, colorFilter);
+
+    mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
+    return *this;
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // Transform
 ////////////////////////////////////////////////////////////////////////////////
 
-GlopBuilder& GlopBuilder::setTransformClip(const Matrix4& ortho,
+GlopBuilder& GlopBuilder::setTransform(const Matrix4& ortho,
         const Matrix4& transform, bool fudgingOffset) {
     TRIGGER_STAGE(kTransformStage);
 
@@ -396,12 +411,13 @@
 
     const Matrix4& canvasTransform = mOutGlop->transform.canvas;
     if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+        // snap by adjusting the model view matrix
         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->fill.texture.filter = GL_NEAREST;
     }
 
     mOutGlop->transform.modelView.loadTranslate(left, top, 0.0f);
@@ -419,6 +435,30 @@
     return *this;
 }
 
+GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
+    TRIGGER_STAGE(kModelViewStage);
+    REQUIRE_STAGES(kTransformStage | kFillStage);
+
+    const Matrix4& canvasTransform = mOutGlop->transform.canvas;
+    if (CC_LIKELY(canvasTransform.isPureTranslate())) {
+        // snap by adjusting the model view matrix
+        const float translateX = canvasTransform.getTranslateX();
+        const float translateY = canvasTransform.getTranslateY();
+
+        offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
+        offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
+        mOutGlop->fill.texture.filter = GL_NEAREST;
+    }
+
+    mOutGlop->transform.modelView.loadTranslate(offsetX, offsetY, 0.0f);
+    mOutGlop->bounds.translate(offsetX, offsetY);
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// RoundRectClip
+////////////////////////////////////////////////////////////////////////////////
+
 GlopBuilder& GlopBuilder::setRoundRectClipState(const RoundRectClipState* roundRectClipState) {
     TRIGGER_STAGE(kRoundRectClipStage);
 
@@ -431,11 +471,17 @@
 // Build
 ////////////////////////////////////////////////////////////////////////////////
 
+void verify(const ProgramDescription& description, const Glop& glop) {
+    bool hasTexture = glop.fill.texture.texture != nullptr;
+    LOG_ALWAYS_FATAL_IF(description.hasTexture != hasTexture);
+    LOG_ALWAYS_FATAL_IF((glop.mesh.vertexFlags & kTextureCoord_Attrib) != hasTexture);
+}
+
 void GlopBuilder::build() {
     REQUIRE_STAGES(kAllStages);
 
     // serialize shader info into ShaderData
-    GLuint textureUnit = mOutGlop->fill.texture ? 1 : 0;
+    GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
     SkiaShader::store(mCaches, mShader, mOutGlop->transform.modelView,
             &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
 
@@ -448,6 +494,8 @@
             && !mDescription.hasGradient
             && !mDescription.hasBitmap;
     mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
+
+    verify(mDescription, *mOutGlop);
 }
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 546e6c5..cbdd0cd 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -39,9 +39,10 @@
     GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
 
     GlopBuilder& setMeshUnitQuad();
-    GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper, bool isAlphaMaskTexture);
+    GlopBuilder& setMeshTexturedUnitQuad(const UvMapper* uvMapper);
     GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer, bool shadowInterp);
     GlopBuilder& setMeshIndexedQuads(void* vertexData, int quadCount);
+    GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
 
     GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale);
     GlopBuilder& setFillTexturePaint(Texture& texture, bool isAlphaMaskTexture,
@@ -52,12 +53,15 @@
             const SkPaint& paint, float alphaScale);
     GlopBuilder& setFillBlack();
     GlopBuilder& setFillClear();
+    GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
+            float alpha, SkXfermode::Mode mode);
 
-    GlopBuilder& setTransformClip(const Matrix4& ortho, const Matrix4& transform, bool fudgingOffset);
+    GlopBuilder& setTransform(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& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
 
     GlopBuilder& setRoundRectClipState(const RoundRectClipState* roundRectClipState);
 
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index fb4c785..ea93e7f 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -166,7 +166,7 @@
     GradientInfo info;
     getGradientInfo(colors, count, info);
 
-    Texture* texture = new Texture();
+    Texture* texture = new Texture(Caches::getInstance());
     texture->width = info.width;
     texture->height = 2;
     texture->blend = info.hasAlpha;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
new file mode 100644
index 0000000..d0ea3a6
--- /dev/null
+++ b/libs/hwui/JankTracker.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 "JankTracker.h"
+
+#include <cstdio>
+#include <inttypes.h>
+
+namespace android {
+namespace uirenderer {
+
+static const char* JANK_TYPE_NAMES[] = {
+        "Missed Vsync",
+        "High input latency",
+        "Slow UI thread",
+        "Slow bitmap uploads",
+        "Slow draw",
+};
+
+struct Comparison {
+    FrameInfoIndex start;
+    FrameInfoIndex end;
+};
+
+static const Comparison COMPARISONS[] = {
+        {FrameInfoIndex::kIntendedVsync, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kOldestInputEvent, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kVsync, FrameInfoIndex::kSyncStart},
+        {FrameInfoIndex::kSyncStart, FrameInfoIndex::kIssueDrawCommandsStart},
+        {FrameInfoIndex::kIssueDrawCommandsStart, FrameInfoIndex::kFrameCompleted},
+};
+
+// If the event exceeds 10 seconds throw it away, this isn't a jank event
+// it's an ANR and will be handled as such
+static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
+
+/*
+ * Frames that are exempt from jank metrics.
+ * First-draw frames, for example, are expected to
+ * be slow, this is hidden from the user with window animations and
+ * other tricks
+ *
+ * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * for now
+ *
+ * TODO: kSurfaceCanvas can negatively impact other drawing by using up
+ * time on the RenderThread, figure out how to attribute that as a jank-causer
+ */
+static const int64_t EXEMPT_FRAMES_FLAGS
+        = FrameInfoFlags::kWindowLayoutChanged
+        | FrameInfoFlags::kSurfaceCanvas;
+
+JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
+    reset();
+    setFrameInterval(frameIntervalNanos);
+}
+
+void JankTracker::setFrameInterval(nsecs_t frameInterval) {
+    mFrameInterval = frameInterval;
+    mThresholds[kMissedVsync] = 1;
+    /*
+     * Due to interpolation and sample rate differences between the touch
+     * panel and the display (example, 85hz touch panel driving a 60hz display)
+     * we call high latency 1.5 * frameinterval
+     *
+     * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel
+     * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms
+     * Thus this must always be larger than frameInterval, or it will fail
+     */
+    mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval);
+
+    // Note that these do not add up to 1. This is intentional. It's to deal
+    // with variance in values, and should be sort of an upper-bound on what
+    // is reasonable to expect.
+    mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
+    mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
+    mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
+
+}
+
+void JankTracker::addFrame(const FrameInfo& frame) {
+    mTotalFrameCount++;
+    // Fast-path for jank-free frames
+    int64_t totalDuration =
+            frame[FrameInfoIndex::kFrameCompleted] - frame[FrameInfoIndex::kIntendedVsync];
+    if (CC_LIKELY(totalDuration < mFrameInterval)) {
+        return;
+    }
+
+    if (frame[FrameInfoIndex::kFlags] & EXEMPT_FRAMES_FLAGS) {
+        return;
+    }
+
+    mJankFrameCount++;
+
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        int64_t delta = frame[COMPARISONS[i].end] - frame[COMPARISONS[i].start];
+        if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
+            mBuckets[i].count++;
+        }
+    }
+}
+
+void JankTracker::dump(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\nFrame stats:");
+    fprintf(file, "\n  Total frames rendered: %u", mTotalFrameCount);
+    fprintf(file, "\n  Janky frames: %u (%.2f%%)", mJankFrameCount,
+            (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        fprintf(file, "\n   Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
+    }
+    fprintf(file, "\n");
+    fflush(file);
+}
+
+void JankTracker::reset() {
+    memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS);
+    mTotalFrameCount = 0;
+    mJankFrameCount = 0;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
new file mode 100644
index 0000000..aa554cd
--- /dev/null
+++ b/libs/hwui/JankTracker.h
@@ -0,0 +1,68 @@
+/*
+ * 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 JANKTRACKER_H_
+#define JANKTRACKER_H_
+
+#include "FrameInfo.h"
+#include "renderthread/TimeLord.h"
+#include "utils/RingBuffer.h"
+
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+enum JankType {
+    kMissedVsync = 0,
+    kHighInputLatency,
+    kSlowUI,
+    kSlowSync,
+    kSlowRT,
+
+    // must be last
+    NUM_BUCKETS,
+};
+
+struct JankBucket {
+    // Number of frames that hit this bucket
+    uint32_t count;
+};
+
+// TODO: Replace DrawProfiler with this
+class JankTracker {
+public:
+    JankTracker(nsecs_t frameIntervalNanos);
+
+    void setFrameInterval(nsecs_t frameIntervalNanos);
+
+    void addFrame(const FrameInfo& frame);
+
+    void dump(int fd);
+    void reset();
+
+private:
+    JankBucket mBuckets[NUM_BUCKETS];
+    int64_t mThresholds[NUM_BUCKETS];
+
+    int64_t mFrameInterval;
+    uint32_t mTotalFrameCount;
+    uint32_t mJankFrameCount;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* JANKTRACKER_H_ */
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 84ff021..3c1f1d1 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -200,10 +200,14 @@
         return stencil;
     }
 
-    inline GLuint getTexture() const {
+    inline GLuint getTextureId() const {
         return texture.id;
     }
 
+    inline Texture& getTexture() {
+        return texture;
+    }
+
     inline GLenum getRenderTarget() const {
         return renderTarget;
     }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index b4b14e8..f598664 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -247,7 +247,7 @@
     }
 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            layer->getTexture(), 0);
+            layer->getTextureId(), 0);
 
     renderState.bindFramebuffer(previousFbo);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 3f79cef..b62af3b 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -753,7 +753,7 @@
     }
 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-            layer->getTexture(), 0);
+            layer->getTextureId(), 0);
 
     // Expand the startTiling region by 1
     startTilingCurrentClip(true, true);
@@ -862,9 +862,9 @@
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(layer->getColorFilter());
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
-        setupDrawTexture(layer->getTexture());
+        setupDrawTexture(layer->getTextureId());
     } else {
-        setupDrawExternalTexture(layer->getTexture());
+        setupDrawExternalTexture(layer->getTextureId());
     }
     if (currentTransform()->isPureTranslate() &&
             !layer->getForceFilter() &&
@@ -924,7 +924,7 @@
 
         bool blend = layer->isBlend() || getLayerAlpha(layer) < 1.0f;
         drawTextureMesh(x, y, x + rect.getWidth(), y + rect.getHeight(),
-                layer->getTexture(), &layerPaint, blend,
+                layer->getTextureId(), &layerPaint, blend,
                 &mMeshVertices[0].x, &mMeshVertices[0].u,
                 GL_TRIANGLE_STRIP, kUnitQuadCount, swap, swap || simpleTransform);
 
@@ -1061,7 +1061,7 @@
     setupDrawDirtyRegionsDisabled();
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms(layer->getColorFilter());
-    setupDrawTexture(layer->getTexture());
+    setupDrawTexture(layer->getTextureId());
     if (currentTransform()->isPureTranslate()) {
         const float x = (int) floorf(rect.left + currentTransform()->getTranslateX() + 0.5f);
         const float y = (int) floorf(rect.top + currentTransform()->getTranslateY() + 0.5f);
@@ -1233,7 +1233,7 @@
             GlopBuilder aBuilder(mRenderState, mCaches, &glop);
             aBuilder.setMeshIndexedQuads(&mesh[0], quadCount)
                     .setFillClear()
-                    .setTransformClip(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                    .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
                     .setModelViewOffsetRect(0, 0, currentSnapshot()->getClipRect())
                     .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                     .build();
@@ -1437,7 +1437,7 @@
         GlopBuilder aBuilder(mRenderState, mCaches, &glop);
         aBuilder.setMeshIndexedQuads(&rectangleVertices[0], rectangleVertices.size() / 4)
                 .setFillBlack()
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), Matrix4::identity(), false)
                 .setModelViewOffsetRect(0, 0, scissorBox)
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -1981,19 +1981,6 @@
 }
 
 void OpenGLRenderer::drawAlphaBitmap(Texture* texture, const SkPaint* paint) {
-    if (USE_GLOPS) {
-        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;
 
@@ -2061,6 +2048,20 @@
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
 
+    if (USE_GLOPS) {
+        bool isAlpha8Texture = bitmap->colorType() == kAlpha_8_SkColorType;
+        Glop glop;
+        GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+        aBuilder.setMeshTexturedUnitQuad(texture->uvMapper)
+                .setFillTexturePaint(*texture, isAlpha8Texture, paint, currentSnapshot()->alpha)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setModelViewMapUnitToRectSnap(Rect(0, 0, texture->width, texture->height))
+                .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                .build();
+        renderGlop(glop);
+        return;
+    }
+
     if (CC_UNLIKELY(bitmap->colorType() == kAlpha_8_SkColorType)) {
         drawAlphaBitmap(texture, paint);
     } else {
@@ -2376,7 +2377,7 @@
         bool shadowInterp = displayFlags & kVertexBuffer_ShadowInterp;
         aBuilder.setMeshVertexBuffer(vertexBuffer, shadowInterp)
                 .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), fudgeOffset)
                 .setModelViewOffsetRect(translateX, translateY, vertexBuffer.getBounds())
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -2692,9 +2693,9 @@
     if (USE_GLOPS) {
         Glop glop;
         GlopBuilder aBuilder(mRenderState, mCaches, &glop);
-        aBuilder.setMeshTexturedUnitQuad(nullptr, true)
+        aBuilder.setMeshTexturedUnitQuad(nullptr)
                 .setFillShadowTexturePaint(*texture, textShadow.color, *paint, currentSnapshot()->alpha)
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
                 .setModelViewMapUnitToRect(Rect(sx, sy, sx + texture->width, sy + texture->height))
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -3048,45 +3049,58 @@
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
                     composeLayerRect(layer, layer->regionRect));
         } else if (layer->mesh) {
-            const float a = getLayerAlpha(layer);
-            setupDraw();
-            setupDrawWithTexture();
-            setupDrawColor(a, a, a, a);
-            setupDrawColorFilter(layer->getColorFilter());
-            setupDrawBlending(layer);
-            setupDrawProgram();
-            setupDrawPureColorUniforms();
-            setupDrawColorFilterUniforms(layer->getColorFilter());
-            setupDrawTexture(layer->getTexture());
-            if (CC_LIKELY(currentTransform()->isPureTranslate())) {
-                int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
-                int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
-
-                layer->setFilter(GL_NEAREST);
-                setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
-                        tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
+            if (USE_GLOPS) {
+                Glop glop;
+                GlopBuilder aBuilder(mRenderState, mCaches, &glop);
+                aBuilder.setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
+                        .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode())
+                        .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                        .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+                        .setRoundRectClipState(currentSnapshot()->roundRectClipState)
+                        .build();
+                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
             } else {
-                layer->setFilter(GL_LINEAR);
-                setupDrawModelView(kModelViewMode_Translate, false, x, y,
-                        x + layer->layer.getWidth(), y + layer->layer.getHeight());
+                const float a = getLayerAlpha(layer);
+                setupDraw();
+                setupDrawWithTexture();
+                setupDrawColor(a, a, a, a);
+                setupDrawColorFilter(layer->getColorFilter());
+                setupDrawBlending(layer);
+                setupDrawProgram();
+                setupDrawPureColorUniforms();
+                setupDrawColorFilterUniforms(layer->getColorFilter());
+                setupDrawTexture(layer->getTextureId());
+                if (CC_LIKELY(currentTransform()->isPureTranslate())) {
+                    int tx = (int) floorf(x + currentTransform()->getTranslateX() + 0.5f);
+                    int ty = (int) floorf(y + currentTransform()->getTranslateY() + 0.5f);
+
+                    layer->setFilter(GL_NEAREST);
+                    setupDrawModelView(kModelViewMode_Translate, false, tx, ty,
+                            tx + layer->layer.getWidth(), ty + layer->layer.getHeight(), true);
+                } else {
+                    layer->setFilter(GL_LINEAR);
+                    setupDrawModelView(kModelViewMode_Translate, false, x, y,
+                            x + layer->layer.getWidth(), y + layer->layer.getHeight());
+                }
+
+
+                TextureVertex* mesh = &layer->mesh[0];
+                GLsizei elementsCount = layer->meshElementCount;
+
+
+                while (elementsCount > 0) {
+                    GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+
+                    setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
+                    DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
+                            glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
+
+                    elementsCount -= drawCount;
+                    // Though there are 4 vertices in a quad, we use 6 indices per
+                    // quad to draw with GL_TRIANGLES
+                    mesh += (drawCount / 6) * 4;
+                }
             }
-
-            TextureVertex* mesh = &layer->mesh[0];
-            GLsizei elementsCount = layer->meshElementCount;
-
-            while (elementsCount > 0) {
-                GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
-
-                setupDrawMeshIndices(&mesh[0].x, &mesh[0].u);
-                DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate,
-                        glDrawElements(GL_TRIANGLES, drawCount, GL_UNSIGNED_SHORT, nullptr));
-
-                elementsCount -= drawCount;
-                // Though there are 4 vertices in a quad, we use 6 indices per
-                // quad to draw with GL_TRIANGLES
-                mesh += (drawCount / 6) * 4;
-            }
-
 #if DEBUG_LAYERS_AS_REGIONS
             drawRegionRectsDebug(layer->region);
 #endif
@@ -3139,9 +3153,9 @@
     if (USE_GLOPS) {
         Glop glop;
         GlopBuilder aBuilder(mRenderState, mCaches, &glop);
-        aBuilder.setMeshTexturedUnitQuad(nullptr, true)
+        aBuilder.setMeshTexturedUnitQuad(nullptr)
                 .setFillPathTexturePaint(*texture, *paint, currentSnapshot()->alpha)
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), *currentTransform(), false)
                 .setModelViewMapUnitToRect(Rect(x, y, x + texture->width, y + texture->height))
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -3303,7 +3317,7 @@
         GlopBuilder aBuilder(mRenderState, mCaches, &glop);
         aBuilder.setMeshIndexedQuads(&mesh[0], count / 4)
                 .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
                 .setModelViewOffsetRect(0, 0, Rect(left, top, right, bottom))
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -3349,7 +3363,7 @@
         GlopBuilder aBuilder(mRenderState, mCaches, &glop);
         aBuilder.setMeshUnitQuad()
                 .setFillPaint(*paint, currentSnapshot()->alpha)
-                .setTransformClip(currentSnapshot()->getOrthoMatrix(), transform, false)
+                .setTransform(currentSnapshot()->getOrthoMatrix(), transform, false)
                 .setModelViewMapUnitToRect(Rect(left, top, right, bottom))
                 .setRoundRectClipState(currentSnapshot()->roundRectClipState)
                 .build();
@@ -3381,19 +3395,6 @@
 }
 
 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;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 659ef6c..c6fdd3f 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -402,9 +402,10 @@
                 clipFlags = 0; // all clipping done by saveLayer
             }
 
-            ATRACE_FORMAT("%s alpha caused %ssaveLayer %dx%d",
-                    getName(), clipFlags ? "" : "unclipped ",
-                    (int)layerBounds.getWidth(), (int)layerBounds.getHeight());
+            ATRACE_FORMAT("%s alpha caused %ssaveLayer %dx%d", getName(),
+                    (saveFlags & SkCanvas::kClipToLayer_SaveFlag) ? "" : "unclipped ",
+                    static_cast<int>(layerBounds.getWidth()),
+                    static_cast<int>(layerBounds.getHeight()));
 
             SaveLayerOp* op = new (handler.allocator()) SaveLayerOp(
                     layerBounds.left, layerBounds.top, layerBounds.right, layerBounds.bottom,
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index ca7f48d..9509c48 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -87,8 +87,8 @@
     reverseReceiverTransform.loadInverse(receiverTransform);
     reverseReceiverTransform.mapPoint3d(adjustedLightCenter);
 
-    if (CC_UNLIKELY(caches.propertyLightDiameter > 0)) {
-        lightRadius = caches.propertyLightDiameter;
+    if (CC_UNLIKELY(caches.propertyLightRadius > 0)) {
+        lightRadius = caches.propertyLightRadius;
     }
 
     // Now light and caster are both in local space, we will check whether
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index de5f91c..3c65705 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -228,21 +228,23 @@
     }
 
     // setup the first glyph position and adjust bounds if needed
+    int xBaseline = 0;
+    int yBaseline = 0;
     if (mCanvas->drawTextAbsolutePos()) {
         bounds.offset(x,y);
-        pointStorage[0].set(x, y);
-    } else {
-        pointStorage[0].set(0, 0);
+        xBaseline = x;
+        yBaseline = y;
     }
+    pointStorage[0].set(xBaseline, yBaseline);
 
     // 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);
+            pointStorage[i].set(xBaseline, 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);
+            pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline);
         }
     }
 
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index 512f5cf..593e918 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -24,46 +24,6 @@
 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(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,
         GLenum renderTarget) {
 
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index d5601f8..dfec462 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -30,8 +30,7 @@
  */
 class Texture {
 public:
-    Texture();
-    Texture(Caches& caches);
+    Texture(Caches& caches) : mCaches(caches) { }
 
     virtual ~Texture() { }
 
@@ -59,62 +58,62 @@
     /**
      * Name of the texture.
      */
-    GLuint id;
+    GLuint id = 0;
     /**
      * Generation of the backing bitmap,
      */
-    uint32_t generation;
+    uint32_t generation = 0;
     /**
      * Indicates whether the texture requires blending.
      */
-    bool blend;
+    bool blend = false;
     /**
      * Width of the backing bitmap.
      */
-    uint32_t width;
+    uint32_t width = 0;
     /**
      * Height of the backing bitmap.
      */
-    uint32_t height;
+    uint32_t height = 0;
     /**
      * Indicates whether this texture should be cleaned up after use.
      */
-    bool cleanup;
+    bool cleanup= false;
     /**
      * Optional, size of the original bitmap.
      */
-    uint32_t bitmapSize;
+    uint32_t bitmapSize = 0;
     /**
      * Indicates whether this texture will use trilinear filtering.
      */
-    bool mipMap;
+    bool mipMap = false;
 
     /**
      * Optional, pointer to a texture coordinates mapper.
      */
-    const UvMapper* uvMapper;
+    const UvMapper* uvMapper = nullptr;
 
     /**
      * Whether or not the Texture is marked in use and thus not evictable for
      * the current frame. This is reset at the start of a new frame.
      */
-    bool isInUse;
+    bool isInUse = false;
 
 private:
     /**
-     * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
+     * Last wrap modes set on this texture.
      */
-    GLenum mWrapS;
-    GLenum mWrapT;
+    GLenum mWrapS = GL_CLAMP_TO_EDGE;
+    GLenum mWrapT = GL_CLAMP_TO_EDGE;
 
     /**
-     * Last filters set on this texture. Defaults to GL_NEAREST.
+     * Last filters set on this texture.
      */
-    GLenum mMinFilter;
-    GLenum mMagFilter;
+    GLenum mMinFilter = GL_NEAREST;
+    GLenum mMagFilter = GL_NEAREST;
 
-    bool mFirstFilter;
-    bool mFirstWrap;
+    bool mFirstFilter = true;
+    bool mFirstWrap = true;
 
     Caches& mCaches;
 }; // struct Texture
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index f4f8e44..b911a0f 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -168,7 +168,7 @@
         }
 
         if (canCache) {
-            texture = new Texture();
+            texture = new Texture(Caches::getInstance());
             texture->bitmapSize = size;
             generateTexture(bitmap, texture, false);
 
@@ -206,7 +206,7 @@
         }
 
         const uint32_t size = bitmap->rowBytes() * bitmap->height();
-        texture = new Texture();
+        texture = new Texture(Caches::getInstance());
         texture->bitmapSize = size;
         generateTexture(bitmap, texture, false);
         texture->cleanup = true;
@@ -216,7 +216,7 @@
 }
 
 Texture* TextureCache::getTransient(const SkBitmap* bitmap) {
-    Texture* texture = new Texture();
+    Texture* texture = new Texture(Caches::getInstance());
     texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
     texture->cleanup = true;
 
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 585fb86..6b00020 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -68,6 +68,7 @@
 
 void MeshState::dump() {
     ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
+    ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
     ALOGD("MeshState vertices: vertex data %p, stride %d",
             mCurrentPositionPointer, mCurrentPositionStride);
     ALOGD("MeshState texCoord: data %p, stride %d",
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index b64dbdc..192bf81 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -253,7 +253,6 @@
         glUniform1f(fill.program->getUniform("roundRectRadius"),
                 roundedOutRadius);
     }
-
     // --------------------------------
     // ---------- Mesh setup ----------
     // --------------------------------
@@ -269,16 +268,16 @@
         // glop.fill.texture always takes slot 0, shader samplers increment from there
         mCaches->textureState().activateTexture(0);
 
-        if (glop.fill.textureClamp != GL_INVALID_ENUM) {
-            glop.fill.texture->setWrap(glop.fill.textureClamp, true);
+        if (glop.fill.texture.clamp != GL_INVALID_ENUM) {
+            glop.fill.texture.texture->setWrap(glop.fill.texture.clamp, true);
         }
-        if (glop.fill.textureFilter != GL_INVALID_ENUM) {
-            glop.fill.texture->setFilter(glop.fill.textureFilter, true);
+        if (glop.fill.texture.filter != GL_INVALID_ENUM) {
+            glop.fill.texture.texture->setFilter(glop.fill.texture.filter, true);
         }
 
-        mCaches->textureState().bindTexture(fill.texture->id);
+        mCaches->textureState().bindTexture(fill.texture.texture->id);
         meshState().enableTexCoordsVertexArray();
-        meshState().bindTexCoordsVertexPointer(force, mesh.texCoordOffset);
+        meshState().bindTexCoordsVertexPointer(force, mesh.texCoordOffset, mesh.stride);
     } else {
         meshState().disableTexCoordsVertexArray();
     }
@@ -313,8 +312,13 @@
         while (elementsCount > 0) {
             GLsizei drawCount = MathUtils::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
 
-            // TODO: this double binds on first pass
-            meshState().bindPositionVertexPointer(true, vertices, mesh.stride);
+            // rebind pointers without forcing, since initial bind handled above
+            meshState().bindPositionVertexPointer(false, vertices, mesh.stride);
+            if (mesh.vertexFlags & kTextureCoord_Attrib) {
+                meshState().bindTexCoordsVertexPointer(false,
+                        vertices + kMeshTextureOffset, mesh.stride);
+            }
+
             glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
             elementsCount -= drawCount;
             vertices += (drawCount / 6) * 4 * mesh.stride;
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index 1a638d2..a211de7 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-#include <renderstate/TextureState.h>
+#include "renderstate/TextureState.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6346479..fcf6eb2 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -48,7 +48,8 @@
         , mCanvas(nullptr)
         , mHaveNewSurface(false)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
-        , mRootRenderNode(rootRenderNode) {
+        , mRootRenderNode(rootRenderNode)
+        , mCurrentFrameInfo(nullptr) {
     mRenderThread.renderState().registerCanvasContext(this);
 }
 
@@ -151,9 +152,13 @@
     }
 }
 
-void CanvasContext::prepareTree(TreeInfo& info) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo) {
     mRenderThread.removeFrameCallback(this);
 
+    mCurrentFrameInfo = &mFrames.next();
+    mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
+    mCurrentFrameInfo->markSyncStart();
+
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
     if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {
@@ -203,6 +208,7 @@
             "drawRenderNode called on a context with no canvas or surface!");
 
     profiler().markPlaybackStart();
+    mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -239,12 +245,19 @@
 
     profiler().markPlaybackEnd();
 
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    mCurrentFrameInfo->markSwapBuffers();
+
     if (drew) {
         swapBuffers();
     } else {
         mEglManager.cancelFrame();
     }
 
+    // TODO: Use a fence for real completion?
+    mCurrentFrameInfo->markFrameCompleted();
+    mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
     profiler().finishFrame();
 }
 
@@ -257,9 +270,14 @@
     ATRACE_CALL();
 
     profiler().startFrame();
+    int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
+    UiFrameInfoBuilder(frameInfo)
+        .addFlag(FrameInfoFlags::kRTAnimation)
+        .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
+                mRenderThread.timeLord().latestVsync());
 
     TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
-    prepareTree(info);
+    prepareTree(info, frameInfo);
     if (info.out.canDrawThisFrame) {
         draw();
     }
@@ -372,6 +390,28 @@
     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
 }
 
+void CanvasContext::dumpFrames(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\n\n---PROFILEDATA---");
+    for (size_t i = 0; i < mFrames.size(); i++) {
+        FrameInfo& frame = mFrames[i];
+        if (frame[FrameInfoIndex::kSyncStart] == 0) {
+            continue;
+        }
+        fprintf(file, "\n");
+        for (int i = 0; i < static_cast<int>(FrameInfoIndex::kNumIndexes); i++) {
+            fprintf(file, "%" PRId64 ",", frame[i]);
+        }
+    }
+    fprintf(file, "\n---PROFILEDATA---\n\n");
+    fflush(file);
+}
+
+void CanvasContext::resetFrameStats() {
+    mFrames.clear();
+    mRenderThread.jankTracker().reset();
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d3fbde8..9a60dc7 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -17,7 +17,14 @@
 #ifndef CANVASCONTEXT_H_
 #define CANVASCONTEXT_H_
 
-#include <set>
+#include "DamageAccumulator.h"
+#include "DrawProfiler.h"
+#include "IContextFactory.h"
+#include "FrameInfo.h"
+#include "RenderNode.h"
+#include "utils/RingBuffer.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
@@ -25,14 +32,7 @@
 #include <utils/Functor.h>
 #include <utils/Vector.h>
 
-#include "../DamageAccumulator.h"
-#include "../DrawProfiler.h"
-#include "../IContextFactory.h"
-#include "../RenderNode.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#define FUNCTOR_PROCESS_DELAY 4
+#include <set>
 
 namespace android {
 namespace uirenderer {
@@ -75,7 +75,7 @@
     void setOpaque(bool opaque);
     void makeCurrent();
     void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
-    void prepareTree(TreeInfo& info);
+    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo);
     void draw();
     void destroy();
 
@@ -103,6 +103,9 @@
 
     DrawProfiler& profiler() { return mProfiler; }
 
+    void dumpFrames(int fd);
+    void resetFrameStats();
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -133,6 +136,9 @@
     const sp<RenderNode> mRootRenderNode;
 
     DrawProfiler mProfiler;
+    FrameInfo* mCurrentFrameInfo;
+    // Ring buffer large enough for 1 second worth of frames
+    RingBuffer<FrameInfo, 60> mFrames;
 
     std::set<RenderNode*> mPrefetechedLayers;
 };
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 4d8a469..f48ee41 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -34,8 +34,6 @@
 DrawFrameTask::DrawFrameTask()
         : mRenderThread(nullptr)
         , mContext(nullptr)
-        , mFrameTimeNanos(0)
-        , mRecordDurationNanos(0)
         , mDensity(1.0f) // safe enough default
         , mSyncResult(kSync_OK) {
 }
@@ -68,18 +66,12 @@
     }
 }
 
-int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
+int DrawFrameTask::drawFrame() {
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
     mSyncResult = kSync_OK;
-    mFrameTimeNanos = frameTimeNanos;
-    mRecordDurationNanos = recordDurationNanos;
     postAndWait();
 
-    // Reset the single-frame data
-    mFrameTimeNanos = 0;
-    mRecordDurationNanos = 0;
-
     return mSyncResult;
 }
 
@@ -93,7 +85,7 @@
     ATRACE_NAME("DrawFrame");
 
     mContext->profiler().setDensity(mDensity);
-    mContext->profiler().startFrame(mRecordDurationNanos);
+    mContext->profiler().startFrame();
 
     bool canUnblockUiThread;
     bool canDrawThisFrame;
@@ -122,7 +114,8 @@
 
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     ATRACE_CALL();
-    mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
+    int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::kVsync)];
+    mRenderThread->timeLord().vsyncReceived(vsync);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
 
@@ -130,7 +123,7 @@
         mContext->processLayerUpdate(mLayers[i].get());
     }
     mLayers.clear();
-    mContext->prepareTree(info);
+    mContext->prepareTree(info, mFrameInfo);
 
     // This is after the prepareTree so that any pending operations
     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 953f012..0e56bea 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -25,6 +25,7 @@
 #include "RenderTask.h"
 
 #include "../Rect.h"
+#include "../FrameInfo.h"
 #include "../TreeInfo.h"
 
 namespace android {
@@ -62,7 +63,9 @@
     void removeLayerUpdate(DeferredLayerUpdater* layer);
 
     void setDensity(float density) { mDensity = density; }
-    int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
+    int drawFrame();
+
+    int64_t* frameInfo() { return mFrameInfo; }
 
     virtual void run() override;
 
@@ -80,12 +83,12 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    nsecs_t mFrameTimeNanos;
-    nsecs_t mRecordDurationNanos;
     float mDensity;
     std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
+
+    int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 4dc4248..0fa2f23 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,14 +16,14 @@
 
 #include "RenderProxy.h"
 
-#include "CanvasContext.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#include "../DeferredLayerUpdater.h"
-#include "../DisplayList.h"
-#include "../LayerRenderer.h"
-#include "../Rect.h"
+#include "DeferredLayerUpdater.h"
+#include "DisplayList.h"
+#include "LayerRenderer.h"
+#include "Rect.h"
+#include "renderthread/CanvasContext.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
@@ -52,6 +52,12 @@
     MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
     ARGS(method) *args = (ARGS(method) *) task->payload()
 
+enum class DumpFlags {
+        kFrameStats = 1 << 0,
+        kReset      = 1 << 1,
+};
+MAKE_FLAGS_ENUM(DumpFlags)
+
 CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
         RenderNode* rootRenderNode, IContextFactory* contextFactory) {
     return new CanvasContext(*args->thread, args->translucent,
@@ -92,7 +98,7 @@
 }
 
 CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
-    args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
+    args->thread->setFrameInterval(args->frameIntervalNanos);
     return nullptr;
 }
 
@@ -175,7 +181,8 @@
 }
 
 void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density) {
+    mDrawFrameTask.setDensity(density);
     SETUP_TASK(setup);
     args->context = mContext;
     args->width = width;
@@ -199,10 +206,12 @@
     post(task);
 }
 
-int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-        float density) {
-    mDrawFrameTask.setDensity(density);
-    return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
+int64_t* RenderProxy::frameInfo() {
+    return mDrawFrameTask.frameInfo();
+}
+
+int RenderProxy::syncAndDrawFrame() {
+    return mDrawFrameTask.drawFrame();
 }
 
 CREATE_BRIDGE1(destroy, CanvasContext* context) {
@@ -375,19 +384,28 @@
     mRenderThread.queueAtFront(task);
 }
 
-CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
+CREATE_BRIDGE3(dumpProfileInfo, CanvasContext* context, int fd, int dumpFlags) {
     args->context->profiler().dumpData(args->fd);
+    if (args->dumpFlags & DumpFlags::kFrameStats) {
+        args->context->dumpFrames(args->fd);
+    }
+    if (args->dumpFlags & DumpFlags::kReset) {
+        args->context->resetFrameStats();
+    }
     return nullptr;
 }
 
-void RenderProxy::dumpProfileInfo(int fd) {
+void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
     SETUP_TASK(dumpProfileInfo);
     args->context = mContext;
     args->fd = fd;
+    args->dumpFlags = dumpFlags;
     postAndWait(task);
 }
 
-CREATE_BRIDGE1(dumpGraphicsMemory, int fd) {
+CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
+    args->thread->jankTracker().dump(args->fd);
+
     FILE *file = fdopen(args->fd, "a");
     if (Caches::hasInstance()) {
         String8 cachesLog;
@@ -403,6 +421,7 @@
 void RenderProxy::dumpGraphicsMemory(int fd) {
     SETUP_TASK(dumpGraphicsMemory);
     args->fd = fd;
+    args->thread = &RenderThread::getInstance();
     staticPostAndWait(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d87e777..19e73e5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -71,10 +71,10 @@
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density);
     ANDROID_API void setOpaque(bool opaque);
-    ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-            float density);
+    ANDROID_API int64_t* frameInfo();
+    ANDROID_API int syncAndDrawFrame();
     ANDROID_API void destroy();
 
     ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
@@ -95,7 +95,7 @@
     ANDROID_API void stopDrawing();
     ANDROID_API void notifyFramePending();
 
-    ANDROID_API void dumpProfileInfo(int fd);
+    ANDROID_API void dumpProfileInfo(int fd, int dumpFlags);
     ANDROID_API static void dumpGraphicsMemory(int fd);
 
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9a0fbad..2a8baa7 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -151,6 +151,11 @@
     LOG_ALWAYS_FATAL("Can't destroy the render thread");
 }
 
+void RenderThread::setFrameInterval(nsecs_t frameInterval) {
+    mTimeLord.setFrameInterval(frameInterval);
+    mJankTracker->setFrameInterval(frameInterval);
+}
+
 void RenderThread::initializeDisplayEventReceiver() {
     LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
     mDisplayEventReceiver = new DisplayEventReceiver();
@@ -167,6 +172,7 @@
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
+    mJankTracker = new JankTracker(mTimeLord.frameIntervalNanos());
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 8fc8ca5..f169424 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,8 +19,8 @@
 
 #include "RenderTask.h"
 
-#include <memory>
-#include <set>
+#include "../JankTracker.h"
+#include "TimeLord.h"
 
 #include <cutils/compiler.h>
 #include <utils/Looper.h>
@@ -28,7 +28,8 @@
 #include <utils/Singleton.h>
 #include <utils/Thread.h>
 
-#include "TimeLord.h"
+#include <memory>
+#include <set>
 
 namespace android {
 
@@ -85,9 +86,12 @@
     // the next vsync. If it is not currently registered this does nothing.
     void pushBackFrameCallback(IFrameCallback* callback);
 
+    void setFrameInterval(nsecs_t frameInterval);
+
     TimeLord& timeLord() { return mTimeLord; }
     RenderState& renderState() { return *mRenderState; }
     EglManager& eglManager() { return *mEglManager; }
+    JankTracker& jankTracker() { return *mJankTracker; }
 
 protected:
     virtual bool threadLoop() override;
@@ -132,6 +136,8 @@
     TimeLord mTimeLord;
     RenderState* mRenderState;
     EglManager* mEglManager;
+
+    JankTracker* mJankTracker = nullptr;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index f187493..f846d6a 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -32,7 +32,7 @@
     return false;
 }
 
-nsecs_t TimeLord::computeFrameTimeMs() {
+nsecs_t TimeLord::computeFrameTimeNanos() {
     // Logic copied from Choreographer.java
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
     nsecs_t jitterNanos = now - mFrameTimeNanos;
@@ -40,7 +40,11 @@
         nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
         mFrameTimeNanos = now - lastFrameOffset;
     }
-    return nanoseconds_to_milliseconds(mFrameTimeNanos);
+    return mFrameTimeNanos;
+}
+
+nsecs_t TimeLord::computeFrameTimeMs() {
+    return nanoseconds_to_milliseconds(computeFrameTimeNanos());
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 7c155d2..5464399 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -29,9 +29,13 @@
 class TimeLord {
 public:
     void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+    nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
+
     // returns true if the vsync is newer, false if it was rejected for staleness
     bool vsyncReceived(nsecs_t vsync);
+    nsecs_t latestVsync() { return mFrameTimeNanos; }
     nsecs_t computeFrameTimeMs();
+    nsecs_t computeFrameTimeNanos();
 
 private:
     friend class RenderThread;
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b6d2c4d..b61d72f 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -85,12 +85,10 @@
         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);
+                dp(800.0f), 255 * 0.075, 255 * 0.15, gDisplay.density);
 
         android::uirenderer::Rect DUMMY;
 
-        std::vector< sp<RenderNode> > cards;
-
         DisplayListRenderer* renderer = startRecording(rootNode);
         animation.createContent(width, height, renderer);
         endRecording(renderer, rootNode);
@@ -100,8 +98,7 @@
 
             ATRACE_NAME("UI-Draw Frame");
             animation.doFrame(i);
-            nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-            proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
+            proxy->syncAndDrawFrame();
         }
 
         sleep(5);
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 5ca9083..49d364e7 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -35,4 +35,12 @@
         static_assert(std::is_standard_layout<Type>::value, \
         #Type " must have standard layout")
 
+#define MAKE_FLAGS_ENUM(enumType) \
+        inline int operator|(enumType lhs, enumType rhs) { \
+            return static_cast<int>(lhs) | static_cast<int>(rhs); \
+        } \
+        inline int operator&(int lhs, enumType rhs) { \
+            return lhs & static_cast<int>(rhs); \
+        }
+
 #endif /* MACROS_H */
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
new file mode 100644
index 0000000..fc9aec0
--- /dev/null
+++ b/libs/hwui/utils/RingBuffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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 RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+
+namespace android {
+namespace uirenderer {
+
+template<class T, size_t SIZE>
+class RingBuffer {
+    PREVENT_COPY_AND_ASSIGN(RingBuffer);
+
+public:
+    RingBuffer() {}
+    ~RingBuffer() {}
+
+    size_t capacity() { return SIZE; }
+    size_t size() { return mCount; }
+
+    T& next() {
+        mHead = (mHead + 1) % SIZE;
+        if (mCount < SIZE) {
+            mCount++;
+        }
+        return mBuffer[mHead];
+    }
+
+    T& front() {
+        return this[0];
+    }
+
+    T& back() {
+        return this[size() - 1];
+    }
+
+    T& operator[](size_t index) {
+        return mBuffer[(mHead + index + 1) % mCount];
+    }
+
+    void clear() {
+        mCount = 0;
+        mHead = -1;
+    }
+
+private:
+    T mBuffer[SIZE];
+    int mHead = -1;
+    size_t mCount = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif /* RINGBUFFER_H_ */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ca242e4..97919a9 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -209,8 +209,23 @@
     @SystemApi
     public final static int FLAG_HW_HOTWORD = 0x1 << 5;
 
+    /**
+     * @hide
+     * Flag requesting audible playback even under limited interruptions.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
+
+    /**
+     * @hide
+     * Flag requesting audible playback even when the underlying stream is muted.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
-            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD;
+            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
+            FLAG_BYPASS_MUTE;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
 
     private int mUsage = USAGE_UNKNOWN;
diff --git a/media/java/android/media/AudioDevicesManager.java b/media/java/android/media/AudioDevicesManager.java
new file mode 100644
index 0000000..bce2100
--- /dev/null
+++ b/media/java/android/media/AudioDevicesManager.java
@@ -0,0 +1,271 @@
+/*
+ * 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.media;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import android.content.Context;
+
+/** @hide
+ * API candidate
+ */
+public class AudioDevicesManager {
+    private static String TAG = "AudioDevicesManager";
+    private static boolean DEBUG = true;
+
+    private AudioManager mAudioManager = null;
+    private OnAmPortUpdateListener mPortListener = null;
+
+    /*
+     * Enum/Selection API
+     */
+    public AudioDevicesManager(Context context) {
+        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+        mPortListener = new OnAmPortUpdateListener();
+        mAudioManager.registerAudioPortUpdateListener(mPortListener);
+    }
+
+    /** @hide
+     * API candidate
+     */
+    //TODO Merge this class into android.media.AudioDevice
+    public class AudioDeviceInfo {
+        private AudioDevicePort mPort = null;
+
+        /** @hide */
+        /* package */ AudioDeviceInfo(AudioDevicePort port) {
+            mPort = port;
+        }
+
+        public int getId() { return mPort.handle().id(); }
+
+        public String getName() { return mPort.name(); }
+
+        public int getType() {
+            return mPort.type();
+        }
+
+        public String getAddress() {
+            return mPort.address();
+        }
+
+        public int getRole() { return mPort.role(); }
+
+        public int[] getSampleRates() { return mPort.samplingRates(); }
+
+        public int[] getChannelMasks() { return mPort.channelMasks(); }
+
+        public int[] getChannelCounts() {
+            int[] masks = getChannelMasks();
+            int[] counts = new int[masks.length];
+            for (int mask_index = 0; mask_index < masks.length; mask_index++) {
+                counts[mask_index] = getRole() == AudioPort.ROLE_SINK
+                        ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
+                        : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+            }
+            return counts;
+        }
+
+        /* The format IDs are in AudioFormat.java */
+        public int[] getFormats() { return mPort.formats(); }
+
+        public String toString() { return "" + getId() + " - " + getName(); }
+    }
+
+    /** @hide */
+    public static final int LIST_DEVICES_OUTPUTS   = 0x0001;
+    /** @hide */
+    public static final int LIST_DEVICES_INPUTS    = 0x0002;
+    /** @hide */
+    public static final int LIST_DEVICES_BUILTIN   = 0x0004;
+    /** @hide */
+    public static final int LIST_DEVICES_USB       = 0x0008;
+    // TODO implement the semantics for these.
+    /** @hide */
+    public static final int LIST_DEVICES_WIRED     = 0x0010;
+    /** @hide */
+    public static final int LIST_DEVICES_UNWIRED   = 0x0020;
+
+    /** @hide */
+    public static final int LIST_DEVICES_ALL = LIST_DEVICES_OUTPUTS | LIST_DEVICES_INPUTS;
+
+    private boolean checkFlags(AudioDevicePort port, int flags) {
+        // Inputs / Outputs
+        boolean passed =
+                port.role() == AudioPort.ROLE_SINK && (flags & LIST_DEVICES_OUTPUTS) != 0 ||
+                port.role() == AudioPort.ROLE_SOURCE && (flags & LIST_DEVICES_INPUTS) != 0;
+
+        // USB
+        if (passed && (flags & LIST_DEVICES_USB) != 0) {
+            int role = port.role();
+            int type = port.type();
+            Slog.i(TAG, "  role:" + role + " type:0x" + Integer.toHexString(type));
+            passed =
+                (role == AudioPort.ROLE_SINK && (type & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                (role == AudioPort.ROLE_SOURCE && (type & AudioSystem.DEVICE_IN_ALL_USB) != 0);
+        }
+
+        return passed;
+    }
+
+    /** @hide */
+    public ArrayList<AudioDeviceInfo> listDevices(int flags) {
+        Slog.i(TAG, "AudioManager.listDevices(" + Integer.toHexString(flags) + ")");
+
+        ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
+        int status = mAudioManager.listAudioDevicePorts(ports);
+
+        Slog.i(TAG, "  status:" + status + " numPorts:" + ports.size());
+
+        ArrayList<AudioDeviceInfo> deviceList = new ArrayList<AudioDeviceInfo>();
+
+        if (status == AudioManager.SUCCESS) {
+            deviceList = new ArrayList<AudioDeviceInfo>();
+             for (AudioDevicePort port : ports) {
+                if (checkFlags(port, flags)) {
+                    deviceList.add(new AudioDeviceInfo(port));
+                }
+            }
+        }
+        return deviceList;
+    }
+
+    private ArrayList<OnAudioDeviceConnectionListener> mDeviceConnectionListeners =
+            new ArrayList<OnAudioDeviceConnectionListener>();
+
+    private HashMap<Integer, AudioPort> mCurrentPortlist =
+            new HashMap<Integer, AudioPort>();
+
+    private ArrayList<AudioDeviceInfo> calcAddedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> addedDevices = new  ArrayList<AudioDeviceInfo>();
+        synchronized(mCurrentPortlist) {
+            for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    if (!mCurrentPortlist.containsKey(portList[portIndex].handle().id())) {
+                        addedDevices.add(new AudioDeviceInfo((AudioDevicePort)portList[portIndex]));
+                    }
+                }
+            }
+        }
+        return addedDevices;
+    }
+
+    private boolean hasPortId(AudioPort[] portList, int id) {
+        for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+            if (portList[portIndex].handle().id() == id) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private ArrayList<AudioDeviceInfo> calcRemovedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> removedDevices = new  ArrayList<AudioDeviceInfo>();
+
+        synchronized (mCurrentPortlist) {
+            Iterator it = mCurrentPortlist.entrySet().iterator();
+            while (it.hasNext()) {
+                HashMap.Entry pairs = (HashMap.Entry)it.next();
+                if (pairs.getValue() instanceof AudioDevicePort) {
+                    if (!hasPortId(portList, ((Integer)pairs.getKey()).intValue())) {
+                        removedDevices.add(new AudioDeviceInfo((AudioDevicePort)pairs.getValue()));
+                    }
+                }
+            }
+        }
+        return removedDevices;
+    }
+
+    private void buildCurrentDevicesList(AudioPort[] portList) {
+        synchronized (mCurrentPortlist) {
+            mCurrentPortlist.clear();
+            for (int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    mCurrentPortlist.put(portList[portIndex].handle().id(),
+                                         (AudioDevicePort)portList[portIndex]);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public void addDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.add(listener);
+        }
+    }
+
+    /** @hide */
+    public void removeDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.remove(listener);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
+        static final String TAG = "OnAmPortUpdateListener";
+        public void onAudioPortListUpdate(AudioPort[] portList) {
+            Slog.i(TAG, "onAudioPortListUpdate() " + portList.length + " ports.");
+            ArrayList<AudioDeviceInfo> addedDevices = calcAddedDevices(portList);
+            ArrayList<AudioDeviceInfo> removedDevices = calcRemovedDevices(portList);
+
+            ArrayList<OnAudioDeviceConnectionListener> listeners = null;
+            synchronized (mDeviceConnectionListeners) {
+                listeners =
+                        new ArrayList<OnAudioDeviceConnectionListener>(mDeviceConnectionListeners);
+            }
+
+            // Connect
+            if (addedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onConnect(addedDevices);
+                }
+            }
+
+            // Disconnect?
+            if (removedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onDisconnect(removedDevices);
+                }
+            }
+
+            buildCurrentDevicesList(portList);
+        }
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void onAudioPatchListUpdate(AudioPatch[] patchList) {
+            Slog.i(TAG, "onAudioPatchListUpdate() " + patchList.length + " patches.");
+        }
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void onServiceDied() {
+            Slog.i(TAG, "onServiceDied()");
+        }
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index da89cf4..9876995 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3459,14 +3459,14 @@
      * @see listAudioPorts(ArrayList<AudioPort>)
      * @hide
      */
-    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+    public int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
         int status = updateAudioPortCache(ports, null);
         if (status == SUCCESS) {
             devices.clear();
             for (int i = 0; i < ports.size(); i++) {
                 if (ports.get(i) instanceof AudioDevicePort) {
-                    devices.add(ports.get(i));
+                    devices.add((AudioDevicePort)ports.get(i));
                 }
             }
         }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index caccb6e..cd78234 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1178,6 +1178,9 @@
     }
 
     private boolean isRestricted() {
+        if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+            return false;
+        }
         try {
             final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType);
             final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 615dac2..fc372eb 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -604,6 +604,7 @@
     private final IAppOpsService mAppOps;
     private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
     private int mUsage = -1;
+    private boolean mBypassInterruptionPolicy;
 
     /**
      * Default constructor. Consider using one of the create() methods for
@@ -1169,6 +1170,9 @@
     private native void _start() throws IllegalStateException;
 
     private boolean isRestricted() {
+        if (mBypassInterruptionPolicy) {
+            return false;
+        }
         try {
             final int usage = mUsage != -1 ? mUsage
                     : AudioAttributes.usageForLegacyStreamType(getAudioStreamType());
@@ -1560,6 +1564,8 @@
             throw new IllegalArgumentException(msg);
         }
         mUsage = attributes.getUsage();
+        mBypassInterruptionPolicy = (attributes.getFlags()
+                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
         Parcel pattributes = Parcel.obtain();
         attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
         setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 81d5afe..97b3f63 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -437,10 +437,7 @@
     public void setCaptureRate(double fps) {
         // Make sure that time lapse is enabled when this method is called.
         setParameter("time-lapse-enable=1");
-
-        double timeBetweenFrameCapture = 1 / fps;
-        long timeBetweenFrameCaptureUs = (long) (1000000 * timeBetweenFrameCapture);
-        setParameter("time-between-time-lapse-frame-capture=" + timeBetweenFrameCaptureUs);
+        setParameter("time-lapse-fps=" + fps);
     }
 
     /**
diff --git a/core/java/android/midi/IMidiDeviceServer.aidl b/media/java/android/media/OnAudioDeviceConnectionListener.java
similarity index 60%
copy from core/java/android/midi/IMidiDeviceServer.aidl
copy to media/java/android/media/OnAudioDeviceConnectionListener.java
index 31fdbbb..4bdd4d0 100644
--- a/core/java/android/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/OnAudioDeviceConnectionListener.java
@@ -1,5 +1,5 @@
 /*
- * 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,13 +14,15 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media;
 
-import android.os.ParcelFileDescriptor;
+import java.util.ArrayList;
 
-/** @hide */
-interface IMidiDeviceServer
-{
-    ParcelFileDescriptor openInputPort(int portNumber);
-    ParcelFileDescriptor openOutputPort(int portNumber);
+/**
+ * @hide
+ * API candidate
+ */
+public abstract class OnAudioDeviceConnectionListener {
+    public void onConnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+    public void onDisconnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
 }
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 32d5b82..db6b38b 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -608,6 +608,9 @@
                 int priority, int loop, float rate);
 
         private boolean isRestricted() {
+            if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+                return false;
+            }
             try {
                 final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
                         mAttributes.getUsage(),
diff --git a/core/java/android/midi/IMidiDeviceServer.aidl b/media/java/android/media/midi/IMidiDeviceServer.aidl
similarity index 96%
rename from core/java/android/midi/IMidiDeviceServer.aidl
rename to media/java/android/media/midi/IMidiDeviceServer.aidl
index 31fdbbb..71914ad 100644
--- a/core/java/android/midi/IMidiDeviceServer.aidl
+++ b/media/java/android/media/midi/IMidiDeviceServer.aidl
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/java/android/midi/IMidiListener.aidl b/media/java/android/media/midi/IMidiListener.aidl
similarity index 91%
rename from core/java/android/midi/IMidiListener.aidl
rename to media/java/android/media/midi/IMidiListener.aidl
index b650593..a4129e9 100644
--- a/core/java/android/midi/IMidiListener.aidl
+++ b/media/java/android/media/midi/IMidiListener.aidl
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
-import android.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceInfo;
 
 /** @hide */
 oneway interface IMidiListener
diff --git a/core/java/android/midi/IMidiManager.aidl b/media/java/android/media/midi/IMidiManager.aidl
similarity index 89%
rename from core/java/android/midi/IMidiManager.aidl
rename to media/java/android/media/midi/IMidiManager.aidl
index 575b525..bba35f5 100644
--- a/core/java/android/midi/IMidiManager.aidl
+++ b/media/java/android/media/midi/IMidiManager.aidl
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
-import android.midi.IMidiDeviceServer;
-import android.midi.IMidiListener;
-import android.midi.MidiDeviceInfo;
+import android.media.midi.IMidiDeviceServer;
+import android.media.midi.IMidiListener;
+import android.media.midi.MidiDeviceInfo;
 import android.os.Bundle;
 import android.os.IBinder;
 
diff --git a/core/java/android/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
similarity index 98%
rename from core/java/android/midi/MidiDevice.java
rename to media/java/android/media/midi/MidiDevice.java
index b91aedf..36710fd 100644
--- a/core/java/android/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
diff --git a/core/java/android/midi/MidiDeviceInfo.aidl b/media/java/android/media/midi/MidiDeviceInfo.aidl
similarity index 95%
rename from core/java/android/midi/MidiDeviceInfo.aidl
rename to media/java/android/media/midi/MidiDeviceInfo.aidl
index 59be059..f2f37a2 100644
--- a/core/java/android/midi/MidiDeviceInfo.aidl
+++ b/media/java/android/media/midi/MidiDeviceInfo.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 parcelable MidiDeviceInfo;
diff --git a/core/java/android/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
similarity index 99%
rename from core/java/android/midi/MidiDeviceInfo.java
rename to media/java/android/media/midi/MidiDeviceInfo.java
index dde2669..fd35052 100644
--- a/core/java/android/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.Bundle;
 import android.os.Parcel;
diff --git a/core/java/android/midi/MidiDeviceServer.java b/media/java/android/media/midi/MidiDeviceServer.java
similarity index 99%
rename from core/java/android/midi/MidiDeviceServer.java
rename to media/java/android/media/midi/MidiDeviceServer.java
index 4a1995f..3317baa 100644
--- a/core/java/android/midi/MidiDeviceServer.java
+++ b/media/java/android/media/midi/MidiDeviceServer.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
diff --git a/core/java/android/midi/MidiInputPort.java b/media/java/android/media/midi/MidiInputPort.java
similarity index 98%
rename from core/java/android/midi/MidiInputPort.java
rename to media/java/android/media/midi/MidiInputPort.java
index 735c68a..730d364 100644
--- a/core/java/android/midi/MidiInputPort.java
+++ b/media/java/android/media/midi/MidiInputPort.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.ParcelFileDescriptor;
 
diff --git a/core/java/android/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
similarity index 79%
rename from core/java/android/midi/MidiManager.java
rename to media/java/android/media/midi/MidiManager.java
index 3a0b064..410120d 100644
--- a/core/java/android/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -14,12 +14,13 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.content.Context;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
 
@@ -50,18 +51,38 @@
 
     // Binder stub for receiving device notifications from MidiService
     private class DeviceListener extends IMidiListener.Stub {
-        private DeviceCallback mCallback;
+        private final DeviceCallback mCallback;
+        private final Handler mHandler;
 
-        public DeviceListener(DeviceCallback callback) {
+        public DeviceListener(DeviceCallback callback, Handler handler) {
             mCallback = callback;
+            mHandler = handler;
         }
 
         public void onDeviceAdded(MidiDeviceInfo device) {
-            mCallback.onDeviceAdded(device);
+            if (mHandler != null) {
+                final MidiDeviceInfo deviceF = device;
+                mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mCallback.onDeviceAdded(deviceF);
+                        }
+                    });
+            } else {
+                mCallback.onDeviceAdded(device);
+            }
         }
 
         public void onDeviceRemoved(MidiDeviceInfo device) {
-            mCallback.onDeviceRemoved(device);
+            if (mHandler != null) {
+                final MidiDeviceInfo deviceF = device;
+                mHandler.post(new Runnable() {
+                        @Override public void run() {
+                            mCallback.onDeviceRemoved(deviceF);
+                        }
+                    });
+            } else {
+                mCallback.onDeviceRemoved(device);
+            }
         }
     }
 
@@ -74,7 +95,7 @@
          *
          * @param device a {@link MidiDeviceInfo} for the newly added device
          */
-        void onDeviceAdded(MidiDeviceInfo device) {
+        public void onDeviceAdded(MidiDeviceInfo device) {
         }
 
         /**
@@ -82,7 +103,7 @@
          *
          * @param device a {@link MidiDeviceInfo} for the removed device
          */
-        void onDeviceRemoved(MidiDeviceInfo device) {
+        public void onDeviceRemoved(MidiDeviceInfo device) {
         }
     }
 
@@ -98,9 +119,12 @@
      * Registers a callback to receive notifications when MIDI devices are added and removed.
      *
      * @param callback a {@link DeviceCallback} for MIDI device notifications
+     * @param handler The {@link android.os.Handler Handler} that will be used for delivering the
+     *                device notifications. If handler is null, then the thread used for the
+     *                callback is unspecified.
      */
-    public void registerDeviceCallback(DeviceCallback callback) {
-        DeviceListener deviceListener = new DeviceListener(callback);
+    public void registerDeviceCallback(DeviceCallback callback, Handler handler) {
+        DeviceListener deviceListener = new DeviceListener(callback, handler);
         try {
             mService.registerListener(mToken, deviceListener);
         } catch (RemoteException e) {
@@ -143,7 +167,7 @@
     /**
      * Opens a MIDI device for reading and writing.
      *
-     * @param deviceInfo a {@link android.midi.MidiDeviceInfo} to open
+     * @param deviceInfo a {@link android.media.midi.MidiDeviceInfo} to open
      * @return a {@link MidiDevice} object for the device
      */
     public MidiDevice openDevice(MidiDeviceInfo deviceInfo) {
diff --git a/core/java/android/midi/MidiOutputPort.java b/media/java/android/media/midi/MidiOutputPort.java
similarity index 98%
rename from core/java/android/midi/MidiOutputPort.java
rename to media/java/android/media/midi/MidiOutputPort.java
index b9512fd..83ddeeb 100644
--- a/core/java/android/midi/MidiOutputPort.java
+++ b/media/java/android/media/midi/MidiOutputPort.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
diff --git a/core/java/android/midi/MidiPort.java b/media/java/android/media/midi/MidiPort.java
similarity index 77%
rename from core/java/android/midi/MidiPort.java
rename to media/java/android/media/midi/MidiPort.java
index 7512a90..4d3c91d 100644
--- a/core/java/android/midi/MidiPort.java
+++ b/media/java/android/media/midi/MidiPort.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import android.util.Log;
 
@@ -33,12 +33,16 @@
     private final int mPortNumber;
 
     /**
-     * Maximum size of a packet that can pass through our ParcelFileDescriptor
+     * Maximum size of a packet that can pass through our ParcelFileDescriptor.
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
-    protected static final int MAX_PACKET_SIZE = 1024;
+    public static final int MAX_PACKET_SIZE = 1024;
 
     /**
      * size of message timestamp in bytes
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
     private static final int TIMESTAMP_SIZE = 8;
 
@@ -65,6 +69,7 @@
      * Called when an IOExeption occurs while sending or receiving data.
      * Subclasses can override to be notified of such errors
      *
+     * @hide
      */
      public void onIOException() {
      }
@@ -77,8 +82,11 @@
      * timestamp is message timestamp to pack
      * dest is buffer to pack into
      * returns size of packed message
+     *
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
-    protected static int packMessage(byte[] message, int offset, int size, long timestamp,
+    public static int packMessage(byte[] message, int offset, int size, long timestamp,
             byte[] dest) {
         if (size + TIMESTAMP_SIZE > MAX_PACKET_SIZE) {
             size = MAX_PACKET_SIZE - TIMESTAMP_SIZE;
@@ -98,8 +106,11 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * returns the offset of the MIDI message in packed buffer
+     *
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
-    protected static int getMessageOffset(byte[] buffer, int bufferLength) {
+    public static int getMessageOffset(byte[] buffer, int bufferLength) {
         // message is at the beginning
         return 0;
     }
@@ -107,8 +118,11 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * returns size of MIDI data in packed buffer
+     *
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
-    protected static int getMessageSize(byte[] buffer, int bufferLength) {
+    public static int getMessageSize(byte[] buffer, int bufferLength) {
         // message length is total buffer length minus size of the timestamp
         return bufferLength - TIMESTAMP_SIZE;
     }
@@ -116,8 +130,11 @@
     /**
      * Utility function for unpacking a MIDI message received from our ParcelFileDescriptor
      * unpacks timestamp from packed buffer
+     *
+     * For internal use only. Implementation details may change in the future.
+     * @hide
      */
-    protected static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
+    public static long getMessageTimeStamp(byte[] buffer, int bufferLength) {
         // timestamp is at end of the packet
         int offset = bufferLength;
         long timestamp = 0;
diff --git a/core/java/android/midi/MidiReceiver.java b/media/java/android/media/midi/MidiReceiver.java
similarity index 93%
rename from core/java/android/midi/MidiReceiver.java
rename to media/java/android/media/midi/MidiReceiver.java
index 16c9bbb..64c0c07 100644
--- a/core/java/android/midi/MidiReceiver.java
+++ b/media/java/android/media/midi/MidiReceiver.java
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 import java.io.IOException;
 
 /**
- * Interface for receiving data from a MIDI device.
+ * Interface for sending and receiving data to and from a MIDI device.
  *
  * CANDIDATE FOR PUBLIC API
  * @hide
diff --git a/core/java/android/midi/MidiSender.java b/media/java/android/media/midi/MidiSender.java
similarity index 97%
rename from core/java/android/midi/MidiSender.java
rename to media/java/android/media/midi/MidiSender.java
index 2b7afad..4550476 100644
--- a/core/java/android/midi/MidiSender.java
+++ b/media/java/android/media/midi/MidiSender.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.midi;
+package android.media.midi;
 
 /**
  * Interface provided by a device to allow attaching
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 5406130..cf69b8f 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -430,7 +430,7 @@
             pData = buffer->data;
             dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
             break;
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // Single plane 16bpp bayer data.
             bytesPerPixel = 2;
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -517,7 +517,7 @@
             pixelStride = 0;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
         case HAL_PIXEL_FORMAT_RGB_565:
             // Single plane 16bpp data.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -584,7 +584,7 @@
             rowStride = buffer->stride;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // In native side, strides are specified in pixels, not in bytes.
             // Single plane 16bpp bayer data. even width/height,
             // row stride multiple of 16 pixels (32 bytes)
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index cff2fc7..7dcaf6d 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -64,6 +64,7 @@
              android:layout_height="wrap_content"
              android:layout_marginBottom="12dp"
              android:src="@drawable/ic_lockscreen_ime"
+             android:contentDescription="@string/accessibility_ime_switch_button"
              android:clickable="true"
              android:padding="8dip"
              android:layout_gravity="end|center_vertical"
diff --git a/packages/Keyguard/res/values-af/strings.xml b/packages/Keyguard/res/values-af/strings.xml
index c34be22..e4b543b 100644
--- a/packages/Keyguard/res/values-af/strings.xml
+++ b/packages/Keyguard/res/values-af/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK-bewerking het misluk!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode is aanvaar!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen diens nie."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-am/strings.xml b/packages/Keyguard/res/values-am/strings.xml
index 3f8c1da..c54656e 100644
--- a/packages/Keyguard/res/values-am/strings.xml
+++ b/packages/Keyguard/res/values-am/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"የሲም PUK ክወና አልተሳካም!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ኮዱ ተቀባይነት አግኝቷል!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ከአገልግሎት መስጫ ክልል ውጪ።"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ar/strings.xml b/packages/Keyguard/res/values-ar/strings.xml
index 347edb4..552680b 100644
--- a/packages/Keyguard/res/values-ar/strings.xml
+++ b/packages/Keyguard/res/values-ar/strings.xml
@@ -116,4 +116,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏أخفقت عملية PUK لبطاقة SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"تم قبول الرمز!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"لا تتوفر خدمة"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-bg/strings.xml b/packages/Keyguard/res/values-bg/strings.xml
index c03fc61..5dcb82c 100644
--- a/packages/Keyguard/res/values-bg/strings.xml
+++ b/packages/Keyguard/res/values-bg/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Операцията с PUK кода за SIM картата не бе успешна!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодът е приет!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Няма покритие."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-bn-rBD/strings.xml b/packages/Keyguard/res/values-bn-rBD/strings.xml
index 97fbc0e..2b13a07 100644
--- a/packages/Keyguard/res/values-bn-rBD/strings.xml
+++ b/packages/Keyguard/res/values-bn-rBD/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"সিম PUK ক্রিয়াকলাপটি ব্যর্থ হয়েছে!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"কোড স্বীকৃত হয়েছে!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"কোনো পরিষেবা নেই৷"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ca/strings.xml b/packages/Keyguard/res/values-ca/strings.xml
index 7310450..e675c7a 100644
--- a/packages/Keyguard/res/values-ca/strings.xml
+++ b/packages/Keyguard/res/values-ca/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Hi ha hagut un problema en l\'operació del PUK de la SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"S\'ha acceptat el codi."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sense servei."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-cs/strings.xml b/packages/Keyguard/res/values-cs/strings.xml
index 7e83314..e1fa6f9 100644
--- a/packages/Keyguard/res/values-cs/strings.xml
+++ b/packages/Keyguard/res/values-cs/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operace pomocí kódu PUK SIM karty se nezdařila!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód byl přijat."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žádný signál."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-da/strings.xml b/packages/Keyguard/res/values-da/strings.xml
index f99479f..77e8ce3 100644
--- a/packages/Keyguard/res/values-da/strings.xml
+++ b/packages/Keyguard/res/values-da/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden til SIM-kortet blev afvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden blev accepteret."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen dækning."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-de/strings.xml b/packages/Keyguard/res/values-de/strings.xml
index bfab539..e21961d 100644
--- a/packages/Keyguard/res/values-de/strings.xml
+++ b/packages/Keyguard/res/values-de/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Fehler beim Entsperren mithilfe des PUK-Codes der SIM-Karte"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code akzeptiert"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Kein Dienst"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-el/strings.xml b/packages/Keyguard/res/values-el/strings.xml
index 5c98566..7084c84 100644
--- a/packages/Keyguard/res/values-el/strings.xml
+++ b/packages/Keyguard/res/values-el/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Αποτυχία λειτουργίας κωδικού PUK κάρτας SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Αποδεκτός κωδικός!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Καμία υπηρεσία."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rGB/strings.xml b/packages/Keyguard/res/values-en-rGB/strings.xml
index 859eee9..ee5da13 100644
--- a/packages/Keyguard/res/values-en-rGB/strings.xml
+++ b/packages/Keyguard/res/values-en-rGB/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-en-rIN/strings.xml b/packages/Keyguard/res/values-en-rIN/strings.xml
index 859eee9..ee5da13 100644
--- a/packages/Keyguard/res/values-en-rIN/strings.xml
+++ b/packages/Keyguard/res/values-en-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK operation failed!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepted"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"No service."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-es-rUS/strings.xml b/packages/Keyguard/res/values-es-rUS/strings.xml
index 0009935..b34dd05 100644
--- a/packages/Keyguard/res/values-es-rUS/strings.xml
+++ b/packages/Keyguard/res/values-es-rUS/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al desbloquear la tarjeta SIM con el PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-es/strings.xml b/packages/Keyguard/res/values-es/strings.xml
index 7b1078f..be3c113 100644
--- a/packages/Keyguard/res/values-es/strings.xml
+++ b/packages/Keyguard/res/values-es/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Error al intentar desbloquear la tarjeta SIM con el código PUK"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sin servicio"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-et-rEE/strings.xml b/packages/Keyguard/res/values-et-rEE/strings.xml
index 0d3abb4..402fc14 100644
--- a/packages/Keyguard/res/values-et-rEE/strings.xml
+++ b/packages/Keyguard/res/values-et-rEE/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-i PUK-koodi toiming ebaõnnestus."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kood on õige."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Teenus puudub."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-eu-rES/strings.xml b/packages/Keyguard/res/values-eu-rES/strings.xml
index a9c0f8c..86850bb 100644
--- a/packages/Keyguard/res/values-eu-rES/strings.xml
+++ b/packages/Keyguard/res/values-eu-rES/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM txartelaren PUK eragiketak huts egin du!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodea onartu da!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Zerbitzurik gabe."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fa/strings.xml b/packages/Keyguard/res/values-fa/strings.xml
index ac819ef..b297f09 100644
--- a/packages/Keyguard/res/values-fa/strings.xml
+++ b/packages/Keyguard/res/values-fa/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏عملیات PUK سیم کارت ناموفق بود!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کد پذیرفته شد!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"خدماتی وجود ندارد."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fi/strings.xml b/packages/Keyguard/res/values-fi/strings.xml
index a69ba60..68f7016 100644
--- a/packages/Keyguard/res/values-fi/strings.xml
+++ b/packages/Keyguard/res/values-fi/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-kortin PUK-toiminto epäonnistui!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koodi hyväksytty!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ei yhteyttä."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fr-rCA/strings.xml b/packages/Keyguard/res/values-fr-rCA/strings.xml
index c44a9dc..2c24f7a 100644
--- a/packages/Keyguard/res/values-fr-rCA/strings.xml
+++ b/packages/Keyguard/res/values-fr-rCA/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Le déverrouillage de la carte SIM par code PUK a échoué."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
 </resources>
diff --git a/packages/Keyguard/res/values-fr/strings.xml b/packages/Keyguard/res/values-fr/strings.xml
index f866edb..77a2d06 100644
--- a/packages/Keyguard/res/values-fr/strings.xml
+++ b/packages/Keyguard/res/values-fr/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Échec du déverrouillage à l\'aide de la clé PUK de la carte SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code accepté."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aucun service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
 </resources>
diff --git a/packages/Keyguard/res/values-gl-rES/strings.xml b/packages/Keyguard/res/values-gl-rES/strings.xml
index 8410848..8e8f5c5 100644
--- a/packages/Keyguard/res/values-gl-rES/strings.xml
+++ b/packages/Keyguard/res/values-gl-rES/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Erro ao tentar desbloquar a tarxeta SIM co código PUK."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceptado"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Non hai servizo."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hi/strings.xml b/packages/Keyguard/res/values-hi/strings.xml
index ad432f7..0cd65b8 100644
--- a/packages/Keyguard/res/values-hi/strings.xml
+++ b/packages/Keyguard/res/values-hi/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK की कार्यवाही विफल रही!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकार किया गया!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कोई सेवा नहीं."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hr/strings.xml b/packages/Keyguard/res/values-hr/strings.xml
index abad969..71410c5 100644
--- a/packages/Keyguard/res/values-hr/strings.xml
+++ b/packages/Keyguard/res/values-hr/strings.xml
@@ -110,4 +110,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacija PUK-a SIM kartice nije uspjela!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kôd je prihvaćen!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nema usluge."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hu/strings.xml b/packages/Keyguard/res/values-hu/strings.xml
index 34f189e..dd43dba 100644
--- a/packages/Keyguard/res/values-hu/strings.xml
+++ b/packages/Keyguard/res/values-hu/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"A SIM kártya PUK-művelete sikertelen!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód elfogadva."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nincs szolgáltatás."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-hy-rAM/strings.xml b/packages/Keyguard/res/values-hy-rAM/strings.xml
index f0575c1..e56642a 100644
--- a/packages/Keyguard/res/values-hy-rAM/strings.xml
+++ b/packages/Keyguard/res/values-hy-rAM/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK գործողությունը ձախողվեց:"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Կոդն ընդունվեց:"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ծառայություն չկա:"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-in/strings.xml b/packages/Keyguard/res/values-in/strings.xml
index 1b0d6ae..29a56ef 100644
--- a/packages/Keyguard/res/values-in/strings.xml
+++ b/packages/Keyguard/res/values-in/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kode Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tidak ada layanan."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-is-rIS/strings.xml b/packages/Keyguard/res/values-is-rIS/strings.xml
index 54aea26..5741cd0 100644
--- a/packages/Keyguard/res/values-is-rIS/strings.xml
+++ b/packages/Keyguard/res/values-is-rIS/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-aðgerð SIM-korts mistókst!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Númer samþykkt!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ekkert símasamband."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-it/strings.xml b/packages/Keyguard/res/values-it/strings.xml
index 30ad3d7..c5c476c 100644
--- a/packages/Keyguard/res/values-it/strings.xml
+++ b/packages/Keyguard/res/values-it/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operazione con PUK della SIM non riuscita."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Codice accettato."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nessun servizio."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-iw/strings.xml b/packages/Keyguard/res/values-iw/strings.xml
index edacb2f..a856ccb 100644
--- a/packages/Keyguard/res/values-iw/strings.xml
+++ b/packages/Keyguard/res/values-iw/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏פעולת קוד ה-PUK של כרטיס ה-SIM נכשלה!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"הקוד התקבל!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"אין קליטה."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ja/strings.xml b/packages/Keyguard/res/values-ja/strings.xml
index eda6217..5c76034 100644
--- a/packages/Keyguard/res/values-ja/strings.xml
+++ b/packages/Keyguard/res/values-ja/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK操作に失敗しました。"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"コードが承認されました。"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"通信サービスはありません。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ka-rGE/strings.xml b/packages/Keyguard/res/values-ka-rGE/strings.xml
index b2d776e..e9c77fd 100644
--- a/packages/Keyguard/res/values-ka-rGE/strings.xml
+++ b/packages/Keyguard/res/values-ka-rGE/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ოპერაცია ჩაიშალა!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"კოდი მიღებულია!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"არ არის სერვისი."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-kk-rKZ/strings.xml b/packages/Keyguard/res/values-kk-rKZ/strings.xml
index 92646f2..85443f6 100644
--- a/packages/Keyguard/res/values-kk-rKZ/strings.xml
+++ b/packages/Keyguard/res/values-kk-rKZ/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK жұмысы орындалмады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код қабылданды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Қызмет көрсетілмейді."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-km-rKH/strings.xml b/packages/Keyguard/res/values-km-rKH/strings.xml
index 1bfc27d..be72fd6 100644
--- a/packages/Keyguard/res/values-km-rKH/strings.xml
+++ b/packages/Keyguard/res/values-km-rKH/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"បាន​បរាជ័យ​ក្នុង​ការ​ប្រតិបត្តិ​​លេខ​កូដ PUK ស៊ីម!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"បាន​ទទួល​យក​លេខ​កូដ​!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"គ្មាន​សេវា​"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-kn-rIN/strings.xml b/packages/Keyguard/res/values-kn-rIN/strings.xml
index 795b666..cfa1ac0 100644
--- a/packages/Keyguard/res/values-kn-rIN/strings.xml
+++ b/packages/Keyguard/res/values-kn-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ಸಿಮ್‌ PUK ಕಾರ್ಯಾಚರಣೆ ವಿಫಲಗೊಂಡಿದೆ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ಕೋಡ್ ಅಂಗೀಕೃತವಾಗಿದೆ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ಯಾವುದೇ ಸೇವೆಯಿಲ್ಲ."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ko/strings.xml b/packages/Keyguard/res/values-ko/strings.xml
index 6d849d2..1ef0c19 100644
--- a/packages/Keyguard/res/values-ko/strings.xml
+++ b/packages/Keyguard/res/values-ko/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 작업이 실패했습니다."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"코드 승인 완료"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"서비스 불가"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ky-rKG/strings.xml b/packages/Keyguard/res/values-ky-rKG/strings.xml
index f827ff3..430c19a 100644
--- a/packages/Keyguard/res/values-ky-rKG/strings.xml
+++ b/packages/Keyguard/res/values-ky-rKG/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM-картанын PUK-кодун ачуу кыйрады!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код кабыл алынды!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Байланыш жок."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lo-rLA/strings.xml b/packages/Keyguard/res/values-lo-rLA/strings.xml
index 8b39e57..17c1c5b 100644
--- a/packages/Keyguard/res/values-lo-rLA/strings.xml
+++ b/packages/Keyguard/res/values-lo-rLA/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK ຂອງ SIM ເຮັດວຽກລົ້ມເຫຼວ!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ລະ​ຫັດ​ຖືກຕອບຮັບແລ້ວ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ບໍ່ມີບໍລິການ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lt/strings.xml b/packages/Keyguard/res/values-lt/strings.xml
index 053d3bf..6d7dcc7 100644
--- a/packages/Keyguard/res/values-lt/strings.xml
+++ b/packages/Keyguard/res/values-lt/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nepavyko atlikti SIM kortelės PUK kodo operacijos."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kodas priimtas."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nėra paslaugos."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-lv/strings.xml b/packages/Keyguard/res/values-lv/strings.xml
index 06bdebb..e1da889 100644
--- a/packages/Keyguard/res/values-lv/strings.xml
+++ b/packages/Keyguard/res/values-lv/strings.xml
@@ -110,4 +110,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM kartes PUK koda ievadīšana neizdevās."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kods ir pieņemts!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Nav pakalpojuma."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mk-rMK/strings.xml b/packages/Keyguard/res/values-mk-rMK/strings.xml
index 29223af..717671b 100644
--- a/packages/Keyguard/res/values-mk-rMK/strings.xml
+++ b/packages/Keyguard/res/values-mk-rMK/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ картичката не се отклучи со ПУК кодот!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кодот е прифатен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нема услуга."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ml-rIN/strings.xml b/packages/Keyguard/res/values-ml-rIN/strings.xml
index ba55f0c6..f39a6b7 100644
--- a/packages/Keyguard/res/values-ml-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ml-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"സിം PUK പ്രവർത്തനം പരാജയപ്പെട്ടു!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"കോഡ് അംഗികരിച്ചു!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"സേവനമൊന്നുമില്ല."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mn-rMN/strings.xml b/packages/Keyguard/res/values-mn-rMN/strings.xml
index 3df10db..2f24901 100644
--- a/packages/Keyguard/res/values-mn-rMN/strings.xml
+++ b/packages/Keyguard/res/values-mn-rMN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"СИМ ПҮК ажиллуулах амжилтгүй боллоо!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код зөвшөөрөгдлөө!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Үйлчилгээ байхгүй."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-mr-rIN/strings.xml b/packages/Keyguard/res/values-mr-rIN/strings.xml
index b906bfc..a86bf60 100644
--- a/packages/Keyguard/res/values-mr-rIN/strings.xml
+++ b/packages/Keyguard/res/values-mr-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"सिम PUK कार्य अयशस्‍वी झाले!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्‍वीकारला!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"सेवा नाही."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ms-rMY/strings.xml b/packages/Keyguard/res/values-ms-rMY/strings.xml
index 265d61d..3d4dee4 100644
--- a/packages/Keyguard/res/values-ms-rMY/strings.xml
+++ b/packages/Keyguard/res/values-ms-rMY/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operasi PUK SIM gagal!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Diterima!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Tiada perkhidmatan."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-my-rMM/strings.xml b/packages/Keyguard/res/values-my-rMM/strings.xml
index ae46e8b..4432ceb 100644
--- a/packages/Keyguard/res/values-my-rMM/strings.xml
+++ b/packages/Keyguard/res/values-my-rMM/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"ပင်နံပါတ် ပြန်ဖွင့်သည့် ကုဒ် လုပ်ဆောင်မှု မအောင်မြင်ပါ"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"ကုဒ်နံပါတ်ကို လက်ခံလိုက်ပါသည်"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ဆားဗစ် မရှိပါ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nb/strings.xml b/packages/Keyguard/res/values-nb/strings.xml
index 695e759..efc25cf 100644
--- a/packages/Keyguard/res/values-nb/strings.xml
+++ b/packages/Keyguard/res/values-nb/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"PUK-koden for SIM-kortet ble avvist."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden er godkjent."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjeneste."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ne-rNP/strings.xml b/packages/Keyguard/res/values-ne-rNP/strings.xml
index 66817ad..7f6843a 100644
--- a/packages/Keyguard/res/values-ne-rNP/strings.xml
+++ b/packages/Keyguard/res/values-ne-rNP/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK राख्‍ने कार्य बिफल भयो!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"कोड स्वीकृत!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"कुनै सेवा छैन।"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-nl/strings.xml b/packages/Keyguard/res/values-nl/strings.xml
index 36784fe..3a8d91c 100644
--- a/packages/Keyguard/res/values-nl/strings.xml
+++ b/packages/Keyguard/res/values-nl/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Bewerking met pukcode voor simkaart is mislukt."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Code geaccepteerd."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Geen service"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index dd7f185..b47b76e 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operacja z kodem PUK karty SIM nie udała się."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod został zaakceptowany."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Brak usługi."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-pt-rPT/strings.xml b/packages/Keyguard/res/values-pt-rPT/strings.xml
index 117a76c..9068898 100644
--- a/packages/Keyguard/res/values-pt-rPT/strings.xml
+++ b/packages/Keyguard/res/values-pt-rPT/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha ao introduzir o PUK do cartão SIM!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceite!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-pt/strings.xml b/packages/Keyguard/res/values-pt/strings.xml
index 06b4dbb..690b693 100644
--- a/packages/Keyguard/res/values-pt/strings.xml
+++ b/packages/Keyguard/res/values-pt/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Falha na operação de PUK do SIM."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Código aceito."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Sem serviço."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ro/strings.xml b/packages/Keyguard/res/values-ro/strings.xml
index 83da487..1e6fc00 100644
--- a/packages/Keyguard/res/values-ro/strings.xml
+++ b/packages/Keyguard/res/values-ro/strings.xml
@@ -110,4 +110,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Deblocarea cu ajutorul codului PUK pentru cardul SIM nu a reușit!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Cod acceptat!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Fără serviciu."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ru/strings.xml b/packages/Keyguard/res/values-ru/strings.xml
index 3137590..48fd4f6 100644
--- a/packages/Keyguard/res/values-ru/strings.xml
+++ b/packages/Keyguard/res/values-ru/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Не удалось разблокировать SIM-карту"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код принят"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Нет сигнала."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-si-rLK/strings.xml b/packages/Keyguard/res/values-si-rLK/strings.xml
index 3ec2b05..740b0ea 100644
--- a/packages/Keyguard/res/values-si-rLK/strings.xml
+++ b/packages/Keyguard/res/values-si-rLK/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK ක්‍රියාවලිය අපොහොසත් විය!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"කේතය පිළිගැණුනි!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"සේවාව නැත."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sk/strings.xml b/packages/Keyguard/res/values-sk/strings.xml
index a58ea46..2fbe838 100644
--- a/packages/Keyguard/res/values-sk/strings.xml
+++ b/packages/Keyguard/res/values-sk/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Operácia kódu PUK karty SIM zlyhala!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kód bol prijatý!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Žiadny signál"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sl/strings.xml b/packages/Keyguard/res/values-sl/strings.xml
index 4a44ae4..a79d99a 100644
--- a/packages/Keyguard/res/values-sl/strings.xml
+++ b/packages/Keyguard/res/values-sl/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Postopek za odklepanje s kodo PUK kartice SIM ni uspel."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koda je sprejeta."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ni storitve."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sr/strings.xml b/packages/Keyguard/res/values-sr/strings.xml
index 22538b1..b7c439b 100644
--- a/packages/Keyguard/res/values-sr/strings.xml
+++ b/packages/Keyguard/res/values-sr/strings.xml
@@ -110,4 +110,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Радња са SIM PUK кодом није успела!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Кôд је прихваћен!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Офлајн сте."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sv/strings.xml b/packages/Keyguard/res/values-sv/strings.xml
index 85b2964..75adc2c 100644
--- a/packages/Keyguard/res/values-sv/strings.xml
+++ b/packages/Keyguard/res/values-sv/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Det gick inte att låsa upp med PUK-koden för SIM-kortet."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Koden godkändes!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ingen tjänst."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-sw/strings.xml b/packages/Keyguard/res/values-sw/strings.xml
index 9195740..886c22e 100644
--- a/packages/Keyguard/res/values-sw/strings.xml
+++ b/packages/Keyguard/res/values-sw/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Utendakazi wa PUK ya SIM umeshindwa!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Msimbo Umekubaliwa!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hakuna huduma."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ta-rIN/strings.xml b/packages/Keyguard/res/values-ta-rIN/strings.xml
index 1950d33..89c1480 100644
--- a/packages/Keyguard/res/values-ta-rIN/strings.xml
+++ b/packages/Keyguard/res/values-ta-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"சிம் PUK செயல்பாடு தோல்வி!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"குறியீடு ஏற்கப்பட்டது!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"சேவை இல்லை."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-te-rIN/strings.xml b/packages/Keyguard/res/values-te-rIN/strings.xml
index 1b91f3e..2f51742 100644
--- a/packages/Keyguard/res/values-te-rIN/strings.xml
+++ b/packages/Keyguard/res/values-te-rIN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"సిమ్ PUK చర్య విఫలమైంది!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"కోడ్ ఆమోదించబడింది!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"సేవ లేదు."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-th/strings.xml b/packages/Keyguard/res/values-th/strings.xml
index 397e887..6d0d026 100644
--- a/packages/Keyguard/res/values-th/strings.xml
+++ b/packages/Keyguard/res/values-th/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"การปลดล็อกด้วย PUK ของซิมล้มเหลว!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"รหัสได้รับการยอมรับ!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"ไม่มีบริการ"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-tl/strings.xml b/packages/Keyguard/res/values-tl/strings.xml
index 35cd62a..8125efe 100644
--- a/packages/Keyguard/res/values-tl/strings.xml
+++ b/packages/Keyguard/res/values-tl/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Nabigo ang operasyon ng SIM PUK!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Tinanggap ang Code!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Walang serbisyo."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-tr/strings.xml b/packages/Keyguard/res/values-tr/strings.xml
index 02b3613..df4b6e7 100644
--- a/packages/Keyguard/res/values-tr/strings.xml
+++ b/packages/Keyguard/res/values-tr/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK işlemi başarısız oldu!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod Kabul Edildi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Hizmet yok."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-uk/strings.xml b/packages/Keyguard/res/values-uk/strings.xml
index 2d0a0ef..9e52283 100644
--- a/packages/Keyguard/res/values-uk/strings.xml
+++ b/packages/Keyguard/res/values-uk/strings.xml
@@ -112,4 +112,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Помилка введення PUK-коду SIM-карти."</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Код прийнято."</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Зв’язку немає."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-ur-rPK/strings.xml b/packages/Keyguard/res/values-ur-rPK/strings.xml
index 081f45b..5cd54c0 100644
--- a/packages/Keyguard/res/values-ur-rPK/strings.xml
+++ b/packages/Keyguard/res/values-ur-rPK/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"‏SIM PUK کارروائی ناکام ہو گئی!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"کوڈ قبول کر لیا گیا!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"کوئی سروس نہیں ہے۔"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-uz-rUZ/strings.xml b/packages/Keyguard/res/values-uz-rUZ/strings.xml
index e9e7e6b..a6852a7 100644
--- a/packages/Keyguard/res/values-uz-rUZ/strings.xml
+++ b/packages/Keyguard/res/values-uz-rUZ/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM karta PUK jarayoni amalga oshmadi!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Kod qabul qilindi!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Aloqa yo‘q."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-vi/strings.xml b/packages/Keyguard/res/values-vi/strings.xml
index 45fe1e7..5727900 100644
--- a/packages/Keyguard/res/values-vi/strings.xml
+++ b/packages/Keyguard/res/values-vi/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Thao tác mã PUK của SIM không thành công!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Mã được chấp nhận!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Không có dịch vụ."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rCN/strings.xml b/packages/Keyguard/res/values-zh-rCN/strings.xml
index 6d5cdb2..a93b54b 100644
--- a/packages/Keyguard/res/values-zh-rCN/strings.xml
+++ b/packages/Keyguard/res/values-zh-rCN/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM卡PUK码操作失败!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"代码正确!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"无服务。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rHK/strings.xml b/packages/Keyguard/res/values-zh-rHK/strings.xml
index 1479da3..55a6a5e 100644
--- a/packages/Keyguard/res/values-zh-rHK/strings.xml
+++ b/packages/Keyguard/res/values-zh-rHK/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zh-rTW/strings.xml b/packages/Keyguard/res/values-zh-rTW/strings.xml
index c943c3a..66c665f 100644
--- a/packages/Keyguard/res/values-zh-rTW/strings.xml
+++ b/packages/Keyguard/res/values-zh-rTW/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"SIM 卡 PUK 碼操作失敗!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"密碼正確!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"沒有服務。"</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
 </resources>
diff --git a/packages/Keyguard/res/values-zu/strings.xml b/packages/Keyguard/res/values-zu/strings.xml
index 0d2b8da..be8900a 100644
--- a/packages/Keyguard/res/values-zu/strings.xml
+++ b/packages/Keyguard/res/values-zu/strings.xml
@@ -108,4 +108,5 @@
     <string name="kg_password_puk_failed" msgid="2838824369502455984">"Umsebenzi we-PUK ye-SIM wehlulekile!"</string>
     <string name="kg_pin_accepted" msgid="1448241673570020097">"Ikhodi yamukelwe!"</string>
     <string name="keyguard_carrier_default" msgid="8700650403054042153">"Ayikho isevisi."</string>
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
 </resources>
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 8b18b2e..5047330 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -297,4 +297,7 @@
         This is displayed if the phone is not connected to a carrier.-->
     <string name="keyguard_carrier_default">No service.</string>
 
+    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">Switch input method button.</string>
+
 </resources>
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..6e29d23
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..6110e9e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..6cca225
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..6445f2a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..78c0294
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..2fcc3b0
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..70d35bf
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-hdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..2d9b75e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-hdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..b6ebe34
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-mdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..8b67b91
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-ldrtl-xhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..1fa0a3d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..175bd78
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..05b27e8
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..6e9f8ae
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..5f3371f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..539d77f
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..3216776
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-mdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..4f381ba
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..c67127d
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..d3b356b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..2d38129
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..fb76575
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..d8b68eb
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..02cc3af
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..7805b7a
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..8127774
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..84b8085
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..289d6ac
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..72bc804
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..e31ce2b
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..f23b0e7
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
new file mode 100644
index 0000000..1e12f96
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_cellphone.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
new file mode 100644
index 0000000..8b547d9
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headphones_a2dp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
new file mode 100644
index 0000000..03c5033
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_headset_hfp.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
new file mode 100644
index 0000000..b9a9923
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_misc_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
new file mode 100644
index 0000000..989e1ab
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_network_pan.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
new file mode 100644
index 0000000..de8c389
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_bt_pointing_hid.png
Binary files differ
diff --git a/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png b/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
new file mode 100644
index 0000000..2eb8a92
--- /dev/null
+++ b/packages/SettingsLib/res/drawable-xxxhdpi/ic_lockscreen_ime.png
Binary files differ
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f055a2c..870afeb 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -67,4 +67,87 @@
 
     <!-- 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>
+
+    <!-- Bluetooth settings.  Message when a device is disconnected -->
+    <string name="bluetooth_disconnected">Disconnected</string>
+    <!-- Bluetooth settings.  Message when disconnecting from a device -->
+    <string name="bluetooth_disconnecting">Disconnecting\u2026</string>
+     <!-- Bluetooth settings.  Message when connecting to a device -->
+    <string name="bluetooth_connecting">Connecting\u2026</string>
+    <!-- Bluetooth settings.  Message when connected to a device. [CHAR LIMIT=40] -->
+    <string name="bluetooth_connected">Connected</string>
+
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the A2DP profile. -->
+    <string name="bluetooth_profile_a2dp">Media audio</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the headset or handsfree profile. -->
+    <string name="bluetooth_profile_headset">Phone audio</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the OPP profile. -->
+    <string name="bluetooth_profile_opp">File transfer</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the HID profile. -->
+    <string name="bluetooth_profile_hid">Input device</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (accessing Internet through remote device). [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pan">Internet access</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PBAP profile. [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pbap">Contact sharing</string>
+    <!-- Bluetooth settings. The user-visible summary string that is used whenever referring to the PBAP profile (sharing contacts). [CHAR LIMIT=60] -->
+    <string name="bluetooth_profile_pbap_summary">Use for contact sharing</string>
+    <!-- Bluetooth settings. The user-visible string that is used whenever referring to the PAN profile (sharing this device's Internet connection). [CHAR LIMIT=40] -->
+    <string name="bluetooth_profile_pan_nap">Internet connection sharing</string>
+    <!-- Bluetooth settings.  The user-visible string that is used whenever referring to the map profile. -->
+    <string name="bluetooth_profile_map">Message Access</string>
+
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the A2DP checkbox preference when A2DP is connected. -->
+    <string name="bluetooth_a2dp_profile_summary_connected">Connected to media audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the headset checkbox preference when headset is connected. -->
+    <string name="bluetooth_headset_profile_summary_connected">Connected to phone audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference when OPP is connected. -->
+    <string name="bluetooth_opp_profile_summary_connected">Connected to file transfer server</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the map checkbox preference when map is connected. -->
+    <string name="bluetooth_map_profile_summary_connected">Connected to map</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference when OPP is not connected. -->
+    <string name="bluetooth_opp_profile_summary_not_connected">Not connected to file transfer server</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the HID checkbox preference when HID is connected. -->
+    <string name="bluetooth_hid_profile_summary_connected">Connected to input device</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (user role). [CHAR LIMIT=25]-->
+    <string name="bluetooth_pan_user_profile_summary_connected">Connected to device for Internet access</string>
+    <!-- Bluetooth settings. Connection options screen. The summary for the checkbox preference when PAN is connected (NAP role). [CHAR LIMIT=25]-->
+    <string name="bluetooth_pan_nap_profile_summary_connected">Sharing local Internet connection with device</string>
+
+    <!-- Bluetooth settings. Connection options screen. The summary
+         for the PAN checkbox preference that describes how checking it
+         will set the PAN profile as preferred. -->
+    <string name="bluetooth_pan_profile_summary_use_for">Use for Internet access</string>
+    <!-- Bluetooth settings. Connection options screen.  The summary for the map checkbox preference that describes how checking it will set the map profile as preferred. -->
+    <string name="bluetooth_map_profile_summary_use_for">Use for map</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the A2DP checkbox preference that describes how checking it will set the A2DP profile as preferred. -->
+    <string name="bluetooth_a2dp_profile_summary_use_for">Use for media audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the headset checkbox preference that describes how checking it will set the headset profile as preferred. -->
+    <string name="bluetooth_headset_profile_summary_use_for">Use for phone audio</string>
+    <!-- Bluetooth settings.  Connection options screen.  The summary for the OPP checkbox preference that describes how checking it will set the OPP profile as preferred. -->
+    <string name="bluetooth_opp_profile_summary_use_for">Use for file transfer</string>
+    <!-- Bluetooth settings. Connection options screen. The summary
+         for the HID checkbox preference that describes how checking it
+         will set the HID profile as preferred. -->
+    <string name="bluetooth_hid_profile_summary_use_for">Use for input</string>
+
+    <!-- Button text for accepting an incoming pairing request. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_accept">Pair</string>
+    <!-- Button text for accepting an incoming pairing request in all caps. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_accept_all_caps">PAIR</string>
+    <!-- Button text for declining an incoming pairing request. [CHAR LIMIT=20] -->
+    <string name="bluetooth_pairing_decline">Cancel</string>
+
+    <!-- Message in pairing dialogs.  [CHAR LIMIT=NONE] -->
+    <string name="bluetooth_pairing_will_share_phonebook">Pairing grants access to your contacts and call history when connected.</string>
+    <!-- Message for the error dialog when BT pairing fails generically. -->
+    <string name="bluetooth_pairing_error_message">Couldn\'t pair with <xliff:g id="device_name">%1$s</xliff:g>.</string>
+
+    <!-- Message for the error dialog when BT pairing fails because the PIN /
+    Passkey entered is incorrect. -->
+    <string name="bluetooth_pairing_pin_error_message">Couldn\'t pair with <xliff:g id="device_name">%1$s</xliff:g> because of an incorrect PIN or passkey.</string>
+    <!-- Message for the error dialog when BT pairing fails because the other device is down. -->
+    <string name="bluetooth_pairing_device_down_error_message">Can\'t communicate with <xliff:g id="device_name">%1$s</xliff:g>.</string>
+    <!-- Message for the error dialog when BT pairing fails because the other device rejected the pairing. -->
+    <string name="bluetooth_pairing_rejected_error_message">Pairing rejected by <xliff:g id="device_name">%1$s</xliff:g>.</string>
+
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
new file mode 100644
index 0000000..58e5e29
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -0,0 +1,106 @@
+/*
+ * 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.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.wifi.WifiManager;
+import android.os.SystemProperties;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+public class TetherUtil {
+
+    // Types of tethering.
+    public static final int TETHERING_INVALID   = -1;
+    public static final int TETHERING_WIFI      = 0;
+    public static final int TETHERING_USB       = 1;
+    public static final int TETHERING_BLUETOOTH = 2;
+
+    // Extras used for communicating with the TetherService.
+    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
+    public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
+    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
+    /**
+     * Tells the service to run a provision check now.
+     */
+    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
+    /**
+     * Enables wifi tethering if the provision check is successful. Used by
+     * QS to enable tethering.
+     */
+    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
+
+    public static ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(Resources
+            .getSystem().getString(com.android.internal.R.string.config_wifi_tether_enable));
+
+    public static boolean setWifiTethering(boolean enable, Context context) {
+        final WifiManager wifiManager =
+                (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        final ContentResolver cr = context.getContentResolver();
+        /**
+         * Disable Wifi if enabling tethering
+         */
+        int wifiState = wifiManager.getWifiState();
+        if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
+                    (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
+            wifiManager.setWifiEnabled(false);
+            Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
+        }
+
+        boolean success = wifiManager.setWifiApEnabled(null, enable);
+        /**
+         *  If needed, restore Wifi on tether disable
+         */
+        if (!enable) {
+            int wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+            if (wifiSavedState == 1) {
+                wifiManager.setWifiEnabled(true);
+                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
+            }
+        }
+        return success;
+    }
+
+    public static boolean isWifiTetherEnabled(Context context) {
+        WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
+        return wifiManager.getWifiApState() == WifiManager.WIFI_AP_STATE_ENABLED;
+    }
+
+    public static boolean isProvisioningNeeded(Context context) {
+        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
+        // ConnectivityManager#enforceTetherChangePermission
+        String[] provisionApp = context.getResources().getStringArray(
+                com.android.internal.R.array.config_mobile_hotspot_provision_app);
+        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
+                || provisionApp == null) {
+            return false;
+        }
+        return (provisionApp.length == 2);
+    }
+
+    public static boolean isTetheringSupported(Context context) {
+        final ConnectivityManager cm =
+                (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
+        return !isSecondaryUser && cm.isTetheringSupported();
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
new file mode 100755
index 0000000..9608daa
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/A2dpProfile.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class A2dpProfile implements LocalBluetoothProfile {
+    private static final String TAG = "A2dpProfile";
+    private static boolean V = false;
+
+    private BluetoothA2dp mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+
+    static final ParcelUuid[] SINK_UUIDS = {
+        BluetoothUuid.AudioSink,
+        BluetoothUuid.AdvAudioDist,
+    };
+
+    static final String NAME = "A2DP";
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 1;
+
+    // These callbacks run on the main thread.
+    private final class A2dpServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothA2dp) proxy;
+            // We just bound to the service, so refresh the UI for any connected A2DP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "A2dpProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(A2dpProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    A2dpProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new A2dpServiceListener(),
+                BluetoothProfile.A2DP);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                mService.disconnect(sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        // Downgrade priority as user is disconnecting the headset.
+        if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON){
+            mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+        }
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+    boolean isA2dpPlaying() {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (!sinks.isEmpty()) {
+            if (mService.isA2dpPlaying(sinks.get(0))) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_a2dp;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_a2dp_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headphones_a2dp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.A2DP,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up A2DP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
new file mode 100644
index 0000000..b802f58
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothCallback.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+
+/**
+ * BluetoothCallback provides a callback interface for the settings
+ * UI to receive events from {@link BluetoothEventManager}.
+ */
+public interface BluetoothCallback {
+    void onBluetoothStateChanged(int bluetoothState);
+    void onScanningStateChanged(boolean started);
+    void onDeviceAdded(CachedBluetoothDevice cachedDevice);
+    void onDeviceDeleted(CachedBluetoothDevice cachedDevice);
+    void onDeviceBondStateChanged(CachedBluetoothDevice cachedDevice, int bondState);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
new file mode 100644
index 0000000..8dec86a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDeviceFilter.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothUuid;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+/**
+ * BluetoothDeviceFilter contains a static method that returns a
+ * Filter object that returns whether or not the BluetoothDevice
+ * passed to it matches the specified filter type constant from
+ * {@link android.bluetooth.BluetoothDevicePicker}.
+ */
+public final class BluetoothDeviceFilter {
+    private static final String TAG = "BluetoothDeviceFilter";
+
+    /** The filter interface to external classes. */
+    public interface Filter {
+        boolean matches(BluetoothDevice device);
+    }
+
+    /** All filter singleton (referenced directly). */
+    public static final Filter ALL_FILTER = new AllFilter();
+
+    /** Bonded devices only filter (referenced directly). */
+    public static final Filter BONDED_DEVICE_FILTER = new BondedDeviceFilter();
+
+    /** Unbonded devices only filter (referenced directly). */
+    public static final Filter UNBONDED_DEVICE_FILTER = new UnbondedDeviceFilter();
+
+    /** Table of singleton filter objects. */
+    private static final Filter[] FILTERS = {
+            ALL_FILTER,             // FILTER_TYPE_ALL
+            new AudioFilter(),      // FILTER_TYPE_AUDIO
+            new TransferFilter(),   // FILTER_TYPE_TRANSFER
+            new PanuFilter(),       // FILTER_TYPE_PANU
+            new NapFilter()         // FILTER_TYPE_NAP
+    };
+
+    /** Private constructor. */
+    private BluetoothDeviceFilter() {
+    }
+
+    /**
+     * Returns the singleton {@link Filter} object for the specified type,
+     * or {@link #ALL_FILTER} if the type value is out of range.
+     *
+     * @param filterType a constant from BluetoothDevicePicker
+     * @return a singleton object implementing the {@link Filter} interface.
+     */
+    public static Filter getFilter(int filterType) {
+        if (filterType >= 0 && filterType < FILTERS.length) {
+            return FILTERS[filterType];
+        } else {
+            Log.w(TAG, "Invalid filter type " + filterType + " for device picker");
+            return ALL_FILTER;
+        }
+    }
+
+    /** Filter that matches all devices. */
+    private static final class AllFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return true;
+        }
+    }
+
+    /** Filter that matches only bonded devices. */
+    private static final class BondedDeviceFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return device.getBondState() == BluetoothDevice.BOND_BONDED;
+        }
+    }
+
+    /** Filter that matches only unbonded devices. */
+    private static final class UnbondedDeviceFilter implements Filter {
+        public boolean matches(BluetoothDevice device) {
+            return device.getBondState() != BluetoothDevice.BOND_BONDED;
+        }
+    }
+
+    /** Parent class of filters based on UUID and/or Bluetooth class. */
+    private abstract static class ClassUuidFilter implements Filter {
+        abstract boolean matches(ParcelUuid[] uuids, BluetoothClass btClass);
+
+        public boolean matches(BluetoothDevice device) {
+            return matches(device.getUuids(), device.getBluetoothClass());
+        }
+    }
+
+    /** Filter that matches devices that support AUDIO profiles. */
+    private static final class AudioFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS)) {
+                    return true;
+                }
+                if (BluetoothUuid.containsAnyUuid(uuids, HeadsetProfile.UUIDS)) {
+                    return true;
+                }
+            } else if (btClass != null) {
+                if (btClass.doesClassMatch(BluetoothClass.PROFILE_A2DP) ||
+                        btClass.doesClassMatch(BluetoothClass.PROFILE_HEADSET)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /** Filter that matches devices that support Object Transfer. */
+    private static final class TransferFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_OPP);
+        }
+    }
+
+    /** Filter that matches devices that support PAN User (PANU) profile. */
+    private static final class PanuFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.PANU)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_PANU);
+        }
+    }
+
+    /** Filter that matches devices that support NAP profile. */
+    private static final class NapFilter extends ClassUuidFilter {
+        @Override
+        boolean matches(ParcelUuid[] uuids, BluetoothClass btClass) {
+            if (uuids != null) {
+                if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP)) {
+                    return true;
+                }
+            }
+            return btClass != null
+                    && btClass.doesClassMatch(BluetoothClass.PROFILE_NAP);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
new file mode 100644
index 0000000..acb7e7a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothDiscoverableTimeoutReceiver.java
@@ -0,0 +1,86 @@
+/*
+ * 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.settingslib.bluetooth;
+
+/* Required to handle timeout notification when phone is suspended */
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
+
+public class BluetoothDiscoverableTimeoutReceiver extends BroadcastReceiver {
+    private static final String TAG = "BluetoothDiscoverableTimeoutReceiver";
+
+    private static final String INTENT_DISCOVERABLE_TIMEOUT =
+        "android.bluetooth.intent.DISCOVERABLE_TIMEOUT";
+
+    public static void setDiscoverableAlarm(Context context, long alarmTime) {
+        Log.d(TAG, "setDiscoverableAlarm(): alarmTime = " + alarmTime);
+
+        Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
+        intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
+        PendingIntent pending = PendingIntent.getBroadcast(
+            context, 0, intent, 0);
+        AlarmManager alarmManager =
+              (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
+
+        if (pending != null) {
+            // Cancel any previous alarms that do the same thing.
+            alarmManager.cancel(pending);
+            Log.d(TAG, "setDiscoverableAlarm(): cancel prev alarm");
+        }
+        pending = PendingIntent.getBroadcast(
+            context, 0, intent, 0);
+
+        alarmManager.set(AlarmManager.RTC_WAKEUP, alarmTime, pending);
+    }
+
+    public static void cancelDiscoverableAlarm(Context context) {
+        Log.d(TAG, "cancelDiscoverableAlarm(): Enter");
+
+        Intent intent = new Intent(INTENT_DISCOVERABLE_TIMEOUT);
+        intent.setClass(context, BluetoothDiscoverableTimeoutReceiver.class);
+        PendingIntent pending = PendingIntent.getBroadcast(
+            context, 0, intent, PendingIntent.FLAG_NO_CREATE);
+        if (pending != null) {
+            // Cancel any previous alarms that do the same thing.
+            AlarmManager alarmManager =
+              (AlarmManager) context.getSystemService (Context.ALARM_SERVICE);
+
+            alarmManager.cancel(pending);
+        }
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        LocalBluetoothAdapter localBluetoothAdapter = LocalBluetoothAdapter.getInstance();
+
+         if(localBluetoothAdapter != null  &&
+            localBluetoothAdapter.getState() == BluetoothAdapter.STATE_ON) {
+            Log.d(TAG, "Disable discoverable...");
+
+            localBluetoothAdapter.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE);
+         } else {
+            Log.e(TAG, "localBluetoothAdapter is NULL!!");
+        }
+    }
+};
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
new file mode 100755
index 0000000..7c92368
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * BluetoothEventManager receives broadcasts and callbacks from the Bluetooth
+ * API and dispatches the event on the UI thread to the right class in the
+ * Settings.
+ */
+public final class BluetoothEventManager {
+    private static final String TAG = "BluetoothEventManager";
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private LocalBluetoothProfileManager mProfileManager;
+    private final IntentFilter mAdapterIntentFilter, mProfileIntentFilter;
+    private final Map<String, Handler> mHandlerMap;
+    private Context mContext;
+
+    private final Collection<BluetoothCallback> mCallbacks =
+            new ArrayList<BluetoothCallback>();
+
+    interface Handler {
+        void onReceive(Context context, Intent intent, BluetoothDevice device);
+    }
+
+    void addHandler(String action, Handler handler) {
+        mHandlerMap.put(action, handler);
+        mAdapterIntentFilter.addAction(action);
+    }
+
+    void addProfileHandler(String action, Handler handler) {
+        mHandlerMap.put(action, handler);
+        mProfileIntentFilter.addAction(action);
+    }
+
+    // Set profile manager after construction due to circular dependency
+    void setProfileManager(LocalBluetoothProfileManager manager) {
+        mProfileManager = manager;
+    }
+
+    BluetoothEventManager(LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager, Context context) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mAdapterIntentFilter = new IntentFilter();
+        mProfileIntentFilter = new IntentFilter();
+        mHandlerMap = new HashMap<String, Handler>();
+        mContext = context;
+
+        // Bluetooth on/off broadcasts
+        addHandler(BluetoothAdapter.ACTION_STATE_CHANGED, new AdapterStateChangedHandler());
+
+        // Discovery broadcasts
+        addHandler(BluetoothAdapter.ACTION_DISCOVERY_STARTED, new ScanningStateChangedHandler(true));
+        addHandler(BluetoothAdapter.ACTION_DISCOVERY_FINISHED, new ScanningStateChangedHandler(false));
+        addHandler(BluetoothDevice.ACTION_FOUND, new DeviceFoundHandler());
+        addHandler(BluetoothDevice.ACTION_DISAPPEARED, new DeviceDisappearedHandler());
+        addHandler(BluetoothDevice.ACTION_NAME_CHANGED, new NameChangedHandler());
+
+        // Pairing broadcasts
+        addHandler(BluetoothDevice.ACTION_BOND_STATE_CHANGED, new BondStateChangedHandler());
+        addHandler(BluetoothDevice.ACTION_PAIRING_CANCEL, new PairingCancelHandler());
+
+        // Fine-grained state broadcasts
+        addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
+        addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
+
+        // Dock event broadcasts
+        addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
+
+        mContext.registerReceiver(mBroadcastReceiver, mAdapterIntentFilter);
+    }
+
+    void registerProfileIntentReceiver() {
+        mContext.registerReceiver(mBroadcastReceiver, mProfileIntentFilter);
+    }
+
+    /** Register to start receiving callbacks for Bluetooth events. */
+    public void registerCallback(BluetoothCallback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    /** Unregister to stop receiving callbacks for Bluetooth events. */
+    public void unregisterCallback(BluetoothCallback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            BluetoothDevice device = intent
+                    .getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+
+            Handler handler = mHandlerMap.get(action);
+            if (handler != null) {
+                handler.onReceive(context, intent, device);
+            }
+        }
+    };
+
+    private class AdapterStateChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                                    BluetoothAdapter.ERROR);
+            // update local profiles and get paired devices
+            mLocalAdapter.setBluetoothStateInt(state);
+            // send callback to update UI and possibly start scanning
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onBluetoothStateChanged(state);
+                }
+            }
+            // Inform CachedDeviceManager that the adapter state has changed
+            mDeviceManager.onBluetoothStateChanged(state);
+        }
+    }
+
+    private class ScanningStateChangedHandler implements Handler {
+        private final boolean mStarted;
+
+        ScanningStateChangedHandler(boolean started) {
+            mStarted = started;
+        }
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onScanningStateChanged(mStarted);
+                }
+            }
+            mDeviceManager.onScanningStateChanged(mStarted);
+        }
+    }
+
+    private class DeviceFoundHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            short rssi = intent.getShortExtra(BluetoothDevice.EXTRA_RSSI, Short.MIN_VALUE);
+            BluetoothClass btClass = intent.getParcelableExtra(BluetoothDevice.EXTRA_CLASS);
+            String name = intent.getStringExtra(BluetoothDevice.EXTRA_NAME);
+            // TODO Pick up UUID. They should be available for 2.1 devices.
+            // Skip for now, there's a bluez problem and we are not getting uuids even for 2.1.
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+                Log.d(TAG, "DeviceFoundHandler created new CachedBluetoothDevice: "
+                        + cachedDevice);
+                // callback to UI to create Preference for new device
+                dispatchDeviceAdded(cachedDevice);
+            }
+            cachedDevice.setRssi(rssi);
+            cachedDevice.setBtClass(btClass);
+            cachedDevice.setNewName(name);
+            cachedDevice.setVisible(true);
+        }
+    }
+
+    private void dispatchDeviceAdded(CachedBluetoothDevice cachedDevice) {
+        synchronized (mCallbacks) {
+            for (BluetoothCallback callback : mCallbacks) {
+                callback.onDeviceAdded(cachedDevice);
+            }
+        }
+    }
+
+    private class DeviceDisappearedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "received ACTION_DISAPPEARED for an unknown device: " + device);
+                return;
+            }
+            if (CachedBluetoothDeviceManager.onDeviceDisappeared(cachedDevice)) {
+                synchronized (mCallbacks) {
+                    for (BluetoothCallback callback : mCallbacks) {
+                        callback.onDeviceDeleted(cachedDevice);
+                    }
+                }
+            }
+        }
+    }
+
+    private class NameChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onDeviceNameUpdated(device);
+        }
+    }
+
+    private class BondStateChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            if (device == null) {
+                Log.e(TAG, "ACTION_BOND_STATE_CHANGED with no EXTRA_DEVICE");
+                return;
+            }
+            int bondState = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE,
+                                               BluetoothDevice.ERROR);
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "CachedBluetoothDevice for device " + device +
+                        " not found, calling readPairedDevices().");
+                if (!readPairedDevices()) {
+                    Log.e(TAG, "Got bonding state changed for " + device +
+                            ", but we have no record of that device.");
+                    return;
+                }
+                cachedDevice = mDeviceManager.findDevice(device);
+                if (cachedDevice == null) {
+                    Log.e(TAG, "Got bonding state changed for " + device +
+                            ", but device not added in cache.");
+                    return;
+                }
+            }
+
+            synchronized (mCallbacks) {
+                for (BluetoothCallback callback : mCallbacks) {
+                    callback.onDeviceBondStateChanged(cachedDevice, bondState);
+                }
+            }
+            cachedDevice.onBondingStateChanged(bondState);
+
+            if (bondState == BluetoothDevice.BOND_NONE) {
+                int reason = intent.getIntExtra(BluetoothDevice.EXTRA_REASON,
+                        BluetoothDevice.ERROR);
+
+                showUnbondMessage(context, cachedDevice.getName(), reason);
+            }
+        }
+
+        /**
+         * Called when we have reached the unbonded state.
+         *
+         * @param reason one of the error reasons from
+         *            BluetoothDevice.UNBOND_REASON_*
+         */
+        private void showUnbondMessage(Context context, String name, int reason) {
+            int errorMsg;
+
+            switch(reason) {
+            case BluetoothDevice.UNBOND_REASON_AUTH_FAILED:
+                errorMsg = R.string.bluetooth_pairing_pin_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_AUTH_REJECTED:
+                errorMsg = R.string.bluetooth_pairing_rejected_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_REMOTE_DEVICE_DOWN:
+                errorMsg = R.string.bluetooth_pairing_device_down_error_message;
+                break;
+            case BluetoothDevice.UNBOND_REASON_DISCOVERY_IN_PROGRESS:
+            case BluetoothDevice.UNBOND_REASON_AUTH_TIMEOUT:
+            case BluetoothDevice.UNBOND_REASON_REPEATED_ATTEMPTS:
+            case BluetoothDevice.UNBOND_REASON_REMOTE_AUTH_CANCELED:
+                errorMsg = R.string.bluetooth_pairing_error_message;
+                break;
+            default:
+                Log.w(TAG, "showUnbondMessage: Not displaying any message for reason: " + reason);
+                return;
+            }
+            Utils.showError(context, name, errorMsg);
+        }
+    }
+
+    private class ClassChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onBtClassChanged(device);
+        }
+    }
+
+    private class UuidChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            mDeviceManager.onUuidChanged(device);
+        }
+    }
+
+    private class PairingCancelHandler implements Handler {
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            if (device == null) {
+                Log.e(TAG, "ACTION_PAIRING_CANCEL with no EXTRA_DEVICE");
+                return;
+            }
+            int errorMsg = R.string.bluetooth_pairing_error_message;
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            Utils.showError(context, cachedDevice.getName(), errorMsg);
+        }
+    }
+
+    private class DockEventHandler implements Handler {
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            // Remove if unpair device upon undocking
+            int anythingButUnDocked = Intent.EXTRA_DOCK_STATE_UNDOCKED + 1;
+            int state = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, anythingButUnDocked);
+            if (state == Intent.EXTRA_DOCK_STATE_UNDOCKED) {
+                if (device != null && device.getBondState() == BluetoothDevice.BOND_NONE) {
+                    CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+                    if (cachedDevice != null) {
+                        cachedDevice.setVisible(false);
+                    }
+                }
+            }
+        }
+    }
+    boolean readPairedDevices() {
+        Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
+        if (bondedDevices == null) {
+            return false;
+        }
+
+        boolean deviceAdded = false;
+        for (BluetoothDevice device : bondedDevices) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, device);
+                dispatchDeviceAdded(cachedDevice);
+                deviceAdded = true;
+            }
+        }
+
+        return deviceAdded;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
new file mode 100755
index 0000000..ddcc49f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -0,0 +1,787 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.ParcelUuid;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+import android.bluetooth.BluetoothAdapter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * CachedBluetoothDevice represents a remote Bluetooth device. It contains
+ * attributes of the device (such as the address, name, RSSI, etc.) and
+ * functionality that can be performed on the device (connect, pair, disconnect,
+ * etc.).
+ */
+public final class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> {
+    private static final String TAG = "CachedBluetoothDevice";
+    private static final boolean DEBUG = Utils.V;
+
+    private final Context mContext;
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final LocalBluetoothProfileManager mProfileManager;
+    private final BluetoothDevice mDevice;
+    private String mName;
+    private short mRssi;
+    private BluetoothClass mBtClass;
+    private HashMap<LocalBluetoothProfile, Integer> mProfileConnectionState;
+
+    private final List<LocalBluetoothProfile> mProfiles =
+            new ArrayList<LocalBluetoothProfile>();
+
+    // List of profiles that were previously in mProfiles, but have been removed
+    private final List<LocalBluetoothProfile> mRemovedProfiles =
+            new ArrayList<LocalBluetoothProfile>();
+
+    // Device supports PANU but not NAP: remove PanProfile after device disconnects from NAP
+    private boolean mLocalNapRoleConnected;
+
+    private boolean mVisible;
+
+    private int mPhonebookPermissionChoice;
+
+    private int mMessagePermissionChoice;
+
+    private int mMessageRejectionCount;
+
+    private final Collection<Callback> mCallbacks = new ArrayList<Callback>();
+
+    // Following constants indicate the user's choices of Phone book/message access settings
+    // User hasn't made any choice or settings app has wiped out the memory
+    public final static int ACCESS_UNKNOWN = 0;
+    // User has accepted the connection and let Settings app remember the decision
+    public final static int ACCESS_ALLOWED = 1;
+    // User has rejected the connection and let Settings app remember the decision
+    public final static int ACCESS_REJECTED = 2;
+
+    // How many times user should reject the connection to make the choice persist.
+    private final static int MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST = 2;
+
+    private final static String MESSAGE_REJECTION_COUNT_PREFS_NAME = "bluetooth_message_reject";
+
+    /**
+     * When we connect to multiple profiles, we only want to display a single
+     * error even if they all fail. This tracks that state.
+     */
+    private boolean mIsConnectingErrorPossible;
+
+    /**
+     * Last time a bt profile auto-connect was attempted.
+     * If an ACTION_UUID intent comes in within
+     * MAX_UUID_DELAY_FOR_AUTO_CONNECT milliseconds, we will try auto-connect
+     * again with the new UUIDs
+     */
+    private long mConnectAttempted;
+
+    // See mConnectAttempted
+    private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
+
+    /** Auto-connect after pairing only if locally initiated. */
+    private boolean mConnectAfterPairing;
+
+    /**
+     * Describes the current device and profile for logging.
+     *
+     * @param profile Profile to describe
+     * @return Description of the device and profile
+     */
+    private String describe(LocalBluetoothProfile profile) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("Address:").append(mDevice);
+        if (profile != null) {
+            sb.append(" Profile:").append(profile);
+        }
+
+        return sb.toString();
+    }
+
+    void onProfileStateChanged(LocalBluetoothProfile profile, int newProfileState) {
+        if (Utils.D) {
+            Log.d(TAG, "onProfileStateChanged: profile " + profile +
+                    " newProfileState " + newProfileState);
+        }
+        if (mLocalAdapter.getBluetoothState() == BluetoothAdapter.STATE_TURNING_OFF)
+        {
+            if (Utils.D) Log.d(TAG, " BT Turninig Off...Profile conn state change ignored...");
+            return;
+        }
+        mProfileConnectionState.put(profile, newProfileState);
+        if (newProfileState == BluetoothProfile.STATE_CONNECTED) {
+            if (profile instanceof MapProfile) {
+                profile.setPreferred(mDevice, true);
+            } else if (!mProfiles.contains(profile)) {
+                mRemovedProfiles.remove(profile);
+                mProfiles.add(profile);
+                if (profile instanceof PanProfile &&
+                        ((PanProfile) profile).isLocalRoleNap(mDevice)) {
+                    // Device doesn't support NAP, so remove PanProfile on disconnect
+                    mLocalNapRoleConnected = true;
+                }
+            }
+        } else if (profile instanceof MapProfile &&
+                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
+            profile.setPreferred(mDevice, false);
+        } else if (mLocalNapRoleConnected && profile instanceof PanProfile &&
+                ((PanProfile) profile).isLocalRoleNap(mDevice) &&
+                newProfileState == BluetoothProfile.STATE_DISCONNECTED) {
+            Log.d(TAG, "Removing PanProfile from device after NAP disconnect");
+            mProfiles.remove(profile);
+            mRemovedProfiles.add(profile);
+            mLocalNapRoleConnected = false;
+        }
+    }
+
+    CachedBluetoothDevice(Context context,
+                          LocalBluetoothAdapter adapter,
+                          LocalBluetoothProfileManager profileManager,
+                          BluetoothDevice device) {
+        mContext = context;
+        mLocalAdapter = adapter;
+        mProfileManager = profileManager;
+        mDevice = device;
+        mProfileConnectionState = new HashMap<LocalBluetoothProfile, Integer>();
+        fillData();
+    }
+
+    public void disconnect() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            disconnect(profile);
+        }
+        // Disconnect  PBAP server in case its connected
+        // This is to ensure all the profiles are disconnected as some CK/Hs do not
+        // disconnect  PBAP connection when HF connection is brought down
+        PbapServerProfile PbapProfile = mProfileManager.getPbapProfile();
+        if (PbapProfile.getConnectionStatus(mDevice) == BluetoothProfile.STATE_CONNECTED)
+        {
+            PbapProfile.disconnect(mDevice);
+        }
+    }
+
+    public void disconnect(LocalBluetoothProfile profile) {
+        if (profile.disconnect(mDevice)) {
+            if (Utils.D) {
+                Log.d(TAG, "Command sent successfully:DISCONNECT " + describe(profile));
+            }
+        }
+    }
+
+    public void connect(boolean connectAllProfiles) {
+        if (!ensurePaired()) {
+            return;
+        }
+
+        mConnectAttempted = SystemClock.elapsedRealtime();
+        connectWithoutResettingTimer(connectAllProfiles);
+    }
+
+    void onBondingDockConnect() {
+        // Attempt to connect if UUIDs are available. Otherwise,
+        // we will connect when the ACTION_UUID intent arrives.
+        connect(false);
+    }
+
+    private void connectWithoutResettingTimer(boolean connectAllProfiles) {
+        // Try to initialize the profiles if they were not.
+        if (mProfiles.isEmpty()) {
+            // if mProfiles is empty, then do not invoke updateProfiles. This causes a race
+            // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated
+            // from bluetooth stack but ACTION.uuid is not sent yet.
+            // Eventually ACTION.uuid will be received which shall trigger the connection of the
+            // various profiles
+            // If UUIDs are not available yet, connect will be happen
+            // upon arrival of the ACTION_UUID intent.
+            Log.d(TAG, "No profiles. Maybe we will connect later");
+            return;
+        }
+
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+
+        int preferredProfiles = 0;
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {
+                if (profile.isPreferred(mDevice)) {
+                    ++preferredProfiles;
+                    connectInt(profile);
+                }
+            }
+        }
+        if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);
+
+        if (preferredProfiles == 0) {
+            connectAutoConnectableProfiles();
+        }
+    }
+
+    private void connectAutoConnectableProfiles() {
+        if (!ensurePaired()) {
+            return;
+        }
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (profile.isAutoConnectable()) {
+                profile.setPreferred(mDevice, true);
+                connectInt(profile);
+            }
+        }
+    }
+
+    /**
+     * Connect this device to the specified profile.
+     *
+     * @param profile the profile to use with the remote device
+     */
+    public void connectProfile(LocalBluetoothProfile profile) {
+        mConnectAttempted = SystemClock.elapsedRealtime();
+        // Reset the only-show-one-error-dialog tracking variable
+        mIsConnectingErrorPossible = true;
+        connectInt(profile);
+        // Refresh the UI based on profile.connect() call
+        refresh();
+    }
+
+    synchronized void connectInt(LocalBluetoothProfile profile) {
+        if (!ensurePaired()) {
+            return;
+        }
+        if (profile.connect(mDevice)) {
+            if (Utils.D) {
+                Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));
+            }
+            return;
+        }
+        Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);
+    }
+
+    private boolean ensurePaired() {
+        if (getBondState() == BluetoothDevice.BOND_NONE) {
+            startPairing();
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    public boolean startPairing() {
+        // Pairing is unreliable while scanning, so cancel discovery
+        if (mLocalAdapter.isDiscovering()) {
+            mLocalAdapter.cancelDiscovery();
+        }
+
+        if (!mDevice.createBond()) {
+            return false;
+        }
+
+        mConnectAfterPairing = true;  // auto-connect after pairing
+        return true;
+    }
+
+    /**
+     * Return true if user initiated pairing on this device. The message text is
+     * slightly different for local vs. remote initiated pairing dialogs.
+     */
+    boolean isUserInitiatedPairing() {
+        return mConnectAfterPairing;
+    }
+
+    public void unpair() {
+        int state = getBondState();
+
+        if (state == BluetoothDevice.BOND_BONDING) {
+            mDevice.cancelBondProcess();
+        }
+
+        if (state != BluetoothDevice.BOND_NONE) {
+            final BluetoothDevice dev = mDevice;
+            if (dev != null) {
+                final boolean successful = dev.removeBond();
+                if (successful) {
+                    if (Utils.D) {
+                        Log.d(TAG, "Command sent successfully:REMOVE_BOND " + describe(null));
+                    }
+                } else if (Utils.V) {
+                    Log.v(TAG, "Framework rejected command immediately:REMOVE_BOND " +
+                            describe(null));
+                }
+            }
+        }
+    }
+
+    public int getProfileConnectionState(LocalBluetoothProfile profile) {
+        if (mProfileConnectionState == null ||
+                mProfileConnectionState.get(profile) == null) {
+            // If cache is empty make the binder call to get the state
+            int state = profile.getConnectionStatus(mDevice);
+            mProfileConnectionState.put(profile, state);
+        }
+        return mProfileConnectionState.get(profile);
+    }
+
+    public void clearProfileConnectionState ()
+    {
+        if (Utils.D) {
+            Log.d(TAG," Clearing all connection state for dev:" + mDevice.getName());
+        }
+        for (LocalBluetoothProfile profile :getProfiles()) {
+            mProfileConnectionState.put(profile, BluetoothProfile.STATE_DISCONNECTED);
+        }
+    }
+
+    // TODO: do any of these need to run async on a background thread?
+    private void fillData() {
+        fetchName();
+        fetchBtClass();
+        updateProfiles();
+        migratePhonebookPermissionChoice();
+        migrateMessagePermissionChoice();
+        fetchMessageRejectionCount();
+
+        mVisible = false;
+        dispatchAttributesChanged();
+    }
+
+    public BluetoothDevice getDevice() {
+        return mDevice;
+    }
+
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * Populate name from BluetoothDevice.ACTION_FOUND intent
+     */
+    void setNewName(String name) {
+        if (mName == null) {
+            mName = name;
+            if (mName == null || TextUtils.isEmpty(mName)) {
+                mName = mDevice.getAddress();
+            }
+            dispatchAttributesChanged();
+        }
+    }
+
+    /**
+     * user changes the device name
+     */
+    public void setName(String name) {
+        if (!mName.equals(name)) {
+            mName = name;
+            mDevice.setAlias(name);
+            dispatchAttributesChanged();
+        }
+    }
+
+    void refreshName() {
+        fetchName();
+        dispatchAttributesChanged();
+    }
+
+    private void fetchName() {
+        mName = mDevice.getAliasName();
+
+        if (TextUtils.isEmpty(mName)) {
+            mName = mDevice.getAddress();
+            if (DEBUG) Log.d(TAG, "Device has no name (yet), use address: " + mName);
+        }
+    }
+
+    void refresh() {
+        dispatchAttributesChanged();
+    }
+
+    public boolean isVisible() {
+        return mVisible;
+    }
+
+    public void setVisible(boolean visible) {
+        if (mVisible != visible) {
+            mVisible = visible;
+            dispatchAttributesChanged();
+        }
+    }
+
+    public int getBondState() {
+        return mDevice.getBondState();
+    }
+
+    void setRssi(short rssi) {
+        if (mRssi != rssi) {
+            mRssi = rssi;
+            dispatchAttributesChanged();
+        }
+    }
+
+    /**
+     * Checks whether we are connected to this device (any profile counts).
+     *
+     * @return Whether it is connected.
+     */
+    public boolean isConnected() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            int status = getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTED) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    public boolean isConnectedProfile(LocalBluetoothProfile profile) {
+        int status = getProfileConnectionState(profile);
+        return status == BluetoothProfile.STATE_CONNECTED;
+
+    }
+
+    public boolean isBusy() {
+        for (LocalBluetoothProfile profile : mProfiles) {
+            int status = getProfileConnectionState(profile);
+            if (status == BluetoothProfile.STATE_CONNECTING
+                    || status == BluetoothProfile.STATE_DISCONNECTING) {
+                return true;
+            }
+        }
+        return getBondState() == BluetoothDevice.BOND_BONDING;
+    }
+
+    /**
+     * Fetches a new value for the cached BT class.
+     */
+    private void fetchBtClass() {
+        mBtClass = mDevice.getBluetoothClass();
+    }
+
+    private boolean updateProfiles() {
+        ParcelUuid[] uuids = mDevice.getUuids();
+        if (uuids == null) return false;
+
+        ParcelUuid[] localUuids = mLocalAdapter.getUuids();
+        if (localUuids == null) return false;
+
+        /**
+         * Now we know if the device supports PBAP, update permissions...
+         */
+        processPhonebookAccess();
+
+        mProfileManager.updateProfiles(uuids, localUuids, mProfiles, mRemovedProfiles,
+                                       mLocalNapRoleConnected, mDevice);
+
+        if (DEBUG) {
+            Log.e(TAG, "updating profiles for " + mDevice.getAliasName());
+            BluetoothClass bluetoothClass = mDevice.getBluetoothClass();
+
+            if (bluetoothClass != null) Log.v(TAG, "Class: " + bluetoothClass.toString());
+            Log.v(TAG, "UUID:");
+            for (ParcelUuid uuid : uuids) {
+                Log.v(TAG, "  " + uuid);
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Refreshes the UI for the BT class, including fetching the latest value
+     * for the class.
+     */
+    void refreshBtClass() {
+        fetchBtClass();
+        dispatchAttributesChanged();
+    }
+
+    /**
+     * Refreshes the UI when framework alerts us of a UUID change.
+     */
+    void onUuidChanged() {
+        updateProfiles();
+
+        if (DEBUG) {
+            Log.e(TAG, "onUuidChanged: Time since last connect"
+                    + (SystemClock.elapsedRealtime() - mConnectAttempted));
+        }
+
+        /*
+         * If a connect was attempted earlier without any UUID, we will do the
+         * connect now.
+         */
+        if (!mProfiles.isEmpty()
+                && (mConnectAttempted + MAX_UUID_DELAY_FOR_AUTO_CONNECT) > SystemClock
+                        .elapsedRealtime()) {
+            connectWithoutResettingTimer(false);
+        }
+        dispatchAttributesChanged();
+    }
+
+    void onBondingStateChanged(int bondState) {
+        if (bondState == BluetoothDevice.BOND_NONE) {
+            mProfiles.clear();
+            mConnectAfterPairing = false;  // cancel auto-connect
+            setPhonebookPermissionChoice(ACCESS_UNKNOWN);
+            setMessagePermissionChoice(ACCESS_UNKNOWN);
+            mMessageRejectionCount = 0;
+            saveMessageRejectionCount();
+        }
+
+        refresh();
+
+        if (bondState == BluetoothDevice.BOND_BONDED) {
+            if (mDevice.isBluetoothDock()) {
+                onBondingDockConnect();
+            } else if (mConnectAfterPairing) {
+                connect(false);
+            }
+            mConnectAfterPairing = false;
+        }
+    }
+
+    void setBtClass(BluetoothClass btClass) {
+        if (btClass != null && mBtClass != btClass) {
+            mBtClass = btClass;
+            dispatchAttributesChanged();
+        }
+    }
+
+    public BluetoothClass getBtClass() {
+        return mBtClass;
+    }
+
+    public List<LocalBluetoothProfile> getProfiles() {
+        return Collections.unmodifiableList(mProfiles);
+    }
+
+    public List<LocalBluetoothProfile> getConnectableProfiles() {
+        List<LocalBluetoothProfile> connectableProfiles =
+                new ArrayList<LocalBluetoothProfile>();
+        for (LocalBluetoothProfile profile : mProfiles) {
+            if (profile.isConnectable()) {
+                connectableProfiles.add(profile);
+            }
+        }
+        return connectableProfiles;
+    }
+
+    public List<LocalBluetoothProfile> getRemovedProfiles() {
+        return mRemovedProfiles;
+    }
+
+    public void registerCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.add(callback);
+        }
+    }
+
+    public void unregisterCallback(Callback callback) {
+        synchronized (mCallbacks) {
+            mCallbacks.remove(callback);
+        }
+    }
+
+    private void dispatchAttributesChanged() {
+        synchronized (mCallbacks) {
+            for (Callback callback : mCallbacks) {
+                callback.onDeviceAttributesChanged();
+            }
+        }
+    }
+
+    @Override
+    public String toString() {
+        return mDevice.toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if ((o == null) || !(o instanceof CachedBluetoothDevice)) {
+            return false;
+        }
+        return mDevice.equals(((CachedBluetoothDevice) o).mDevice);
+    }
+
+    @Override
+    public int hashCode() {
+        return mDevice.getAddress().hashCode();
+    }
+
+    // This comparison uses non-final fields so the sort order may change
+    // when device attributes change (such as bonding state). Settings
+    // will completely refresh the device list when this happens.
+    public int compareTo(CachedBluetoothDevice another) {
+        // Connected above not connected
+        int comparison = (another.isConnected() ? 1 : 0) - (isConnected() ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Paired above not paired
+        comparison = (another.getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0) -
+            (getBondState() == BluetoothDevice.BOND_BONDED ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Visible above not visible
+        comparison = (another.mVisible ? 1 : 0) - (mVisible ? 1 : 0);
+        if (comparison != 0) return comparison;
+
+        // Stronger signal above weaker signal
+        comparison = another.mRssi - mRssi;
+        if (comparison != 0) return comparison;
+
+        // Fallback on name
+        return mName.compareTo(another.mName);
+    }
+
+    public interface Callback {
+        void onDeviceAttributesChanged();
+    }
+
+    public int getPhonebookPermissionChoice() {
+        int permission = mDevice.getPhonebookAccessPermission();
+        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
+            return ACCESS_ALLOWED;
+        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
+            return ACCESS_REJECTED;
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    public void setPhonebookPermissionChoice(int permissionChoice) {
+        int permission = BluetoothDevice.ACCESS_UNKNOWN;
+        if (permissionChoice == ACCESS_ALLOWED) {
+            permission = BluetoothDevice.ACCESS_ALLOWED;
+        } else if (permissionChoice == ACCESS_REJECTED) {
+            permission = BluetoothDevice.ACCESS_REJECTED;
+        }
+        mDevice.setPhonebookAccessPermission(permission);
+    }
+
+    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
+    // app's shared preferences).
+    private void migratePhonebookPermissionChoice() {
+        SharedPreferences preferences = mContext.getSharedPreferences(
+                "bluetooth_phonebook_permission", Context.MODE_PRIVATE);
+        if (!preferences.contains(mDevice.getAddress())) {
+            return;
+        }
+
+        if (mDevice.getPhonebookAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
+            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
+            if (oldPermission == ACCESS_ALLOWED) {
+                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
+            } else if (oldPermission == ACCESS_REJECTED) {
+                mDevice.setPhonebookAccessPermission(BluetoothDevice.ACCESS_REJECTED);
+            }
+        }
+
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.remove(mDevice.getAddress());
+        editor.commit();
+    }
+
+    public int getMessagePermissionChoice() {
+        int permission = mDevice.getMessageAccessPermission();
+        if (permission == BluetoothDevice.ACCESS_ALLOWED) {
+            return ACCESS_ALLOWED;
+        } else if (permission == BluetoothDevice.ACCESS_REJECTED) {
+            return ACCESS_REJECTED;
+        }
+        return ACCESS_UNKNOWN;
+    }
+
+    public void setMessagePermissionChoice(int permissionChoice) {
+        int permission = BluetoothDevice.ACCESS_UNKNOWN;
+        if (permissionChoice == ACCESS_ALLOWED) {
+            permission = BluetoothDevice.ACCESS_ALLOWED;
+        } else if (permissionChoice == ACCESS_REJECTED) {
+            permission = BluetoothDevice.ACCESS_REJECTED;
+        }
+        mDevice.setMessageAccessPermission(permission);
+    }
+
+    // Migrates data from old data store (in Settings app's shared preferences) to new (in Bluetooth
+    // app's shared preferences).
+    private void migrateMessagePermissionChoice() {
+        SharedPreferences preferences = mContext.getSharedPreferences(
+                "bluetooth_message_permission", Context.MODE_PRIVATE);
+        if (!preferences.contains(mDevice.getAddress())) {
+            return;
+        }
+
+        if (mDevice.getMessageAccessPermission() == BluetoothDevice.ACCESS_UNKNOWN) {
+            int oldPermission = preferences.getInt(mDevice.getAddress(), ACCESS_UNKNOWN);
+            if (oldPermission == ACCESS_ALLOWED) {
+                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_ALLOWED);
+            } else if (oldPermission == ACCESS_REJECTED) {
+                mDevice.setMessageAccessPermission(BluetoothDevice.ACCESS_REJECTED);
+            }
+        }
+
+        SharedPreferences.Editor editor = preferences.edit();
+        editor.remove(mDevice.getAddress());
+        editor.commit();
+    }
+
+    /**
+     * @return Whether this rejection should persist.
+     */
+    public boolean checkAndIncreaseMessageRejectionCount() {
+        if (mMessageRejectionCount < MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST) {
+            mMessageRejectionCount++;
+            saveMessageRejectionCount();
+        }
+        return mMessageRejectionCount >= MESSAGE_REJECTION_COUNT_LIMIT_TO_PERSIST;
+    }
+
+    private void fetchMessageRejectionCount() {
+        SharedPreferences preference = mContext.getSharedPreferences(
+                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE);
+        mMessageRejectionCount = preference.getInt(mDevice.getAddress(), 0);
+    }
+
+    private void saveMessageRejectionCount() {
+        SharedPreferences.Editor editor = mContext.getSharedPreferences(
+                MESSAGE_REJECTION_COUNT_PREFS_NAME, Context.MODE_PRIVATE).edit();
+        if (mMessageRejectionCount == 0) {
+            editor.remove(mDevice.getAddress());
+        } else {
+            editor.putInt(mDevice.getAddress(), mMessageRejectionCount);
+        }
+        editor.commit();
+    }
+
+    private void processPhonebookAccess() {
+        if (mDevice.getBondState() != BluetoothDevice.BOND_BONDED) return;
+
+        ParcelUuid[] uuids = mDevice.getUuids();
+        if (BluetoothUuid.containsAnyUuid(uuids, PbapServerProfile.PBAB_CLIENT_UUIDS)) {
+            // The pairing dialog now warns of phone-book access for paired devices.
+            // No separate prompt is displayed after pairing.
+            setPhonebookPermissionChoice(CachedBluetoothDevice.ACCESS_ALLOWED);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
new file mode 100755
index 0000000..65db95f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -0,0 +1,172 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.content.Context;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices.
+ */
+public final class CachedBluetoothDeviceManager {
+    private static final String TAG = "CachedBluetoothDeviceManager";
+    private static final boolean DEBUG = Utils.D;
+
+    private Context mContext;
+    private final List<CachedBluetoothDevice> mCachedDevices =
+            new ArrayList<CachedBluetoothDevice>();
+
+    CachedBluetoothDeviceManager(Context context) {
+        mContext = context;
+    }
+
+    public synchronized Collection<CachedBluetoothDevice> getCachedDevicesCopy() {
+        return new ArrayList<CachedBluetoothDevice>(mCachedDevices);
+    }
+
+    public static boolean onDeviceDisappeared(CachedBluetoothDevice cachedDevice) {
+        cachedDevice.setVisible(false);
+        return cachedDevice.getBondState() == BluetoothDevice.BOND_NONE;
+    }
+
+    public void onDeviceNameUpdated(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.refreshName();
+        }
+    }
+
+    /**
+     * Search for existing {@link CachedBluetoothDevice} or return null
+     * if this device isn't in the cache. Use {@link #addDevice}
+     * to create and return a new {@link CachedBluetoothDevice} for
+     * a newly discovered {@link BluetoothDevice}.
+     *
+     * @param device the address of the Bluetooth device
+     * @return the cached device object for this device, or null if it has
+     *   not been previously seen
+     */
+    public CachedBluetoothDevice findDevice(BluetoothDevice device) {
+        for (CachedBluetoothDevice cachedDevice : mCachedDevices) {
+            if (cachedDevice.getDevice().equals(device)) {
+                return cachedDevice;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create and return a new {@link CachedBluetoothDevice}. This assumes
+     * that {@link #findDevice} has already been called and returned null.
+     * @param device the address of the new Bluetooth device
+     * @return the newly created CachedBluetoothDevice object
+     */
+    public CachedBluetoothDevice addDevice(LocalBluetoothAdapter adapter,
+            LocalBluetoothProfileManager profileManager,
+            BluetoothDevice device) {
+        CachedBluetoothDevice newDevice = new CachedBluetoothDevice(mContext, adapter,
+            profileManager, device);
+        synchronized (mCachedDevices) {
+            mCachedDevices.add(newDevice);
+        }
+        return newDevice;
+    }
+
+    /**
+     * Attempts to get the name of a remote device, otherwise returns the address.
+     *
+     * @param device The remote device.
+     * @return The name, or if unavailable, the address.
+     */
+    public String getName(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            return cachedDevice.getName();
+        }
+
+        String name = device.getAliasName();
+        if (name != null) {
+            return name;
+        }
+
+        return device.getAddress();
+    }
+
+    public synchronized void clearNonBondedDevices() {
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                mCachedDevices.remove(i);
+            }
+        }
+    }
+
+    public synchronized void onScanningStateChanged(boolean started) {
+        if (!started) return;
+
+        // If starting a new scan, clear old visibility
+        // Iterate in reverse order since devices may be removed.
+        for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+            CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+            cachedDevice.setVisible(false);
+        }
+    }
+
+    public synchronized void onBtClassChanged(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.refreshBtClass();
+        }
+    }
+
+    public synchronized void onUuidChanged(BluetoothDevice device) {
+        CachedBluetoothDevice cachedDevice = findDevice(device);
+        if (cachedDevice != null) {
+            cachedDevice.onUuidChanged();
+        }
+    }
+
+    public synchronized void onBluetoothStateChanged(int bluetoothState) {
+        // When Bluetooth is turning off, we need to clear the non-bonded devices
+        // Otherwise, they end up showing up on the next BT enable
+        if (bluetoothState == BluetoothAdapter.STATE_TURNING_OFF) {
+            for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
+                CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
+                if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+                    cachedDevice.setVisible(false);
+                    mCachedDevices.remove(i);
+                } else {
+                    // For bonded devices, we need to clear the connection status so that
+                    // when BT is enabled next time, device connection status shall be retrieved
+                    // by making a binder call.
+                    cachedDevice.clearProfileConnectionState();
+                }
+            }
+        }
+    }
+    private void log(String msg) {
+        if (DEBUG) {
+            Log.d(TAG, msg);
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
new file mode 100755
index 0000000..5529866
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -0,0 +1,227 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * HeadsetProfile handles Bluetooth HFP and Headset profiles.
+ */
+public final class HeadsetProfile implements LocalBluetoothProfile {
+    private static final String TAG = "HeadsetProfile";
+    private static boolean V = true;
+
+    private BluetoothHeadset mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final ParcelUuid[] UUIDS = {
+        BluetoothUuid.HSP,
+        BluetoothUuid.Handsfree,
+    };
+
+    static final String NAME = "HEADSET";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 0;
+
+    // These callbacks run on the main thread.
+    private final class HeadsetServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothHeadset) proxy;
+            // We just bound to the service, so refresh the UI for any connected HFP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "HeadsetProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(HeadsetProfile.this,
+                        BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+
+            mProfileManager.callServiceConnectedListeners();
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mProfileManager.callServiceDisconnectedListeners();
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    HeadsetProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new HeadsetServiceListener(),
+                BluetoothProfile.HEADSET);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                Log.d(TAG,"Not disconnecting device = " + sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty()) {
+            for (BluetoothDevice dev : deviceList) {
+                if (dev.equals(device)) {
+                    if (V) Log.d(TAG,"Downgrade priority as user" +
+                                        "is disconnecting the headset");
+                    // Downgrade priority as user is disconnecting the headset.
+                    if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                        mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+                    }
+                    return mService.disconnect(device);
+                }
+            }
+        }
+        return false;
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty()){
+            for (BluetoothDevice dev : deviceList) {
+                if (dev.equals(device)) {
+                    return mService.getConnectionState(device);
+                }
+            }
+        }
+        return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_headset;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_headset_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_headset_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_headset_hfp;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.HEADSET,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up HID proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
new file mode 100755
index 0000000..a9e8db5
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -0,0 +1,201 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.List;
+
+/**
+ * HidProfile handles Bluetooth HID profile.
+ */
+public final class HidProfile implements LocalBluetoothProfile {
+    private static final String TAG = "HidProfile";
+    private static boolean V = true;
+
+    private BluetoothInputDevice mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final String NAME = "HID";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 3;
+
+    // These callbacks run on the main thread.
+    private final class InputDeviceServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothInputDevice) proxy;
+            // We just bound to the service, so refresh the UI for any connected HID devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "HidProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(HidProfile.this, BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    HidProfile(Context context, LocalBluetoothAdapter adapter,
+        CachedBluetoothDeviceManager deviceManager,
+        LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        adapter.getProfileProxy(context, new InputDeviceServiceListener(),
+                BluetoothProfile.INPUT_DEVICE);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+
+        return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+                ? mService.getConnectionState(device)
+                : BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        // TODO: distinguish between keyboard and mouse?
+        return R.string.bluetooth_profile_hid;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_hid_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_hid_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        if (btClass == null) {
+            return R.drawable.ic_lockscreen_ime;
+        }
+        return getHidClassDrawable(btClass);
+    }
+
+    public static int getHidClassDrawable(BluetoothClass btClass) {
+        switch (btClass.getDeviceClass()) {
+            case BluetoothClass.Device.PERIPHERAL_KEYBOARD:
+            case BluetoothClass.Device.PERIPHERAL_KEYBOARD_POINTING:
+                return R.drawable.ic_lockscreen_ime;
+            case BluetoothClass.Device.PERIPHERAL_POINTING:
+                return R.drawable.ic_bt_pointing_hid;
+            default:
+                return R.drawable.ic_bt_misc_hid;
+        }
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.INPUT_DEVICE,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up HID proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
new file mode 100644
index 0000000..0c1adec
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothAdapter.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.Set;
+
+/**
+ * LocalBluetoothAdapter provides an interface between the Settings app
+ * and the functionality of the local {@link BluetoothAdapter}, specifically
+ * those related to state transitions of the adapter itself.
+ *
+ * <p>Connection and bonding state changes affecting specific devices
+ * are handled by {@link CachedBluetoothDeviceManager},
+ * {@link BluetoothEventManager}, and {@link LocalBluetoothProfileManager}.
+ */
+public final class LocalBluetoothAdapter {
+    private static final String TAG = "LocalBluetoothAdapter";
+
+    /** This class does not allow direct access to the BluetoothAdapter. */
+    private final BluetoothAdapter mAdapter;
+
+    private LocalBluetoothProfileManager mProfileManager;
+
+    private static LocalBluetoothAdapter sInstance;
+
+    private int mState = BluetoothAdapter.ERROR;
+
+    private static final int SCAN_EXPIRATION_MS = 5 * 60 * 1000; // 5 mins
+
+    private long mLastScan;
+
+    private LocalBluetoothAdapter(BluetoothAdapter adapter) {
+        mAdapter = adapter;
+    }
+
+    void setProfileManager(LocalBluetoothProfileManager manager) {
+        mProfileManager = manager;
+    }
+
+    /**
+     * Get the singleton instance of the LocalBluetoothAdapter. If this device
+     * doesn't support Bluetooth, then null will be returned. Callers must be
+     * prepared to handle a null return value.
+     * @return the LocalBluetoothAdapter object, or null if not supported
+     */
+    static synchronized LocalBluetoothAdapter getInstance() {
+        if (sInstance == null) {
+            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+            if (adapter != null) {
+                sInstance = new LocalBluetoothAdapter(adapter);
+            }
+        }
+
+        return sInstance;
+    }
+
+    // Pass-through BluetoothAdapter methods that we can intercept if necessary
+
+    public void cancelDiscovery() {
+        mAdapter.cancelDiscovery();
+    }
+
+    public boolean enable() {
+        return mAdapter.enable();
+    }
+
+    public boolean disable() {
+        return mAdapter.disable();
+    }
+
+    void getProfileProxy(Context context,
+            BluetoothProfile.ServiceListener listener, int profile) {
+        mAdapter.getProfileProxy(context, listener, profile);
+    }
+
+    public Set<BluetoothDevice> getBondedDevices() {
+        return mAdapter.getBondedDevices();
+    }
+
+    public String getName() {
+        return mAdapter.getName();
+    }
+
+    public int getScanMode() {
+        return mAdapter.getScanMode();
+    }
+
+    public int getState() {
+        return mAdapter.getState();
+    }
+
+    public ParcelUuid[] getUuids() {
+        return mAdapter.getUuids();
+    }
+
+    public boolean isDiscovering() {
+        return mAdapter.isDiscovering();
+    }
+
+    public boolean isEnabled() {
+        return mAdapter.isEnabled();
+    }
+
+    public void setDiscoverableTimeout(int timeout) {
+        mAdapter.setDiscoverableTimeout(timeout);
+    }
+
+    public void setName(String name) {
+        mAdapter.setName(name);
+    }
+
+    public void setScanMode(int mode) {
+        mAdapter.setScanMode(mode);
+    }
+
+    public boolean setScanMode(int mode, int duration) {
+        return mAdapter.setScanMode(mode, duration);
+    }
+
+    public void startScanning(boolean force) {
+        // Only start if we're not already scanning
+        if (!mAdapter.isDiscovering()) {
+            if (!force) {
+                // Don't scan more than frequently than SCAN_EXPIRATION_MS,
+                // unless forced
+                if (mLastScan + SCAN_EXPIRATION_MS > System.currentTimeMillis()) {
+                    return;
+                }
+
+                // If we are playing music, don't scan unless forced.
+                A2dpProfile a2dp = mProfileManager.getA2dpProfile();
+                if (a2dp != null && a2dp.isA2dpPlaying()) {
+                    return;
+                }
+            }
+
+            if (mAdapter.startDiscovery()) {
+                mLastScan = System.currentTimeMillis();
+            }
+        }
+    }
+
+    public void stopScanning() {
+        if (mAdapter.isDiscovering()) {
+            mAdapter.cancelDiscovery();
+        }
+    }
+
+    public synchronized int getBluetoothState() {
+        // Always sync state, in case it changed while paused
+        syncBluetoothState();
+        return mState;
+    }
+
+    synchronized void setBluetoothStateInt(int state) {
+        mState = state;
+
+        if (state == BluetoothAdapter.STATE_ON) {
+            // if mProfileManager hasn't been constructed yet, it will
+            // get the adapter UUIDs in its constructor when it is.
+            if (mProfileManager != null) {
+                mProfileManager.setBluetoothStateOn();
+            }
+        }
+    }
+
+    // Returns true if the state changed; false otherwise.
+    boolean syncBluetoothState() {
+        int currentState = mAdapter.getState();
+        if (currentState != mState) {
+            setBluetoothStateInt(mAdapter.getState());
+            return true;
+        }
+        return false;
+    }
+
+    public void setBluetoothEnabled(boolean enabled) {
+        boolean success = enabled
+                ? mAdapter.enable()
+                : mAdapter.disable();
+
+        if (success) {
+            setBluetoothStateInt(enabled
+                ? BluetoothAdapter.STATE_TURNING_ON
+                : BluetoothAdapter.STATE_TURNING_OFF);
+        } else {
+            if (Utils.V) {
+                Log.v(TAG, "setBluetoothEnabled call, manager didn't return " +
+                        "success for enabled: " + enabled);
+            }
+
+            syncBluetoothState();
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
new file mode 100644
index 0000000..4adc62e
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.content.Context;
+import android.util.Log;
+
+/**
+ * LocalBluetoothManager provides a simplified interface on top of a subset of
+ * the Bluetooth API. Note that {@link #getInstance} will return null
+ * if there is no Bluetooth adapter on this device, and callers must be
+ * prepared to handle this case.
+ */
+public final class LocalBluetoothManager {
+    private static final String TAG = "LocalBluetoothManager";
+
+    /** Singleton instance. */
+    private static LocalBluetoothManager sInstance;
+
+    private final Context mContext;
+
+    /** If a BT-related activity is in the foreground, this will be it. */
+    private Context mForegroundActivity;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+
+    private final CachedBluetoothDeviceManager mCachedDeviceManager;
+
+    /** The Bluetooth profile manager. */
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    /** The broadcast receiver event manager. */
+    private final BluetoothEventManager mEventManager;
+
+    public static synchronized LocalBluetoothManager getInstance(Context context,
+            BluetoothManagerCallback onInitCallback) {
+        if (sInstance == null) {
+            LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance();
+            if (adapter == null) {
+                return null;
+            }
+            // This will be around as long as this process is
+            Context appContext = context.getApplicationContext();
+            sInstance = new LocalBluetoothManager(adapter, appContext);
+            if (onInitCallback != null) {
+                onInitCallback.onBluetoothManagerInitialized(appContext, sInstance);
+            }
+        }
+
+        return sInstance;
+    }
+
+    private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) {
+        mContext = context;
+        mLocalAdapter = adapter;
+
+        mCachedDeviceManager = new CachedBluetoothDeviceManager(context);
+        mEventManager = new BluetoothEventManager(mLocalAdapter,
+                mCachedDeviceManager, context);
+        mProfileManager = new LocalBluetoothProfileManager(context,
+                mLocalAdapter, mCachedDeviceManager, mEventManager);
+    }
+
+    public LocalBluetoothAdapter getBluetoothAdapter() {
+        return mLocalAdapter;
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public Context getForegroundActivity() {
+        return mForegroundActivity;
+    }
+
+    public boolean isForegroundActivity() {
+        return mForegroundActivity != null;
+    }
+
+    public synchronized void setForegroundActivity(Context context) {
+        if (context != null) {
+            Log.d(TAG, "setting foreground activity to non-null context");
+            mForegroundActivity = context;
+        } else {
+            if (mForegroundActivity != null) {
+                Log.d(TAG, "setting foreground activity to null");
+                mForegroundActivity = null;
+            }
+        }
+    }
+
+    public CachedBluetoothDeviceManager getCachedDeviceManager() {
+        return mCachedDeviceManager;
+    }
+
+    public BluetoothEventManager getEventManager() {
+        return mEventManager;
+    }
+
+    public LocalBluetoothProfileManager getProfileManager() {
+        return mProfileManager;
+    }
+
+    public interface BluetoothManagerCallback {
+        void onBluetoothManagerInitialized(Context appContext,
+                LocalBluetoothManager bluetoothManager);
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
new file mode 100755
index 0000000..abcb989
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfile.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+
+/**
+ * LocalBluetoothProfile is an interface defining the basic
+ * functionality related to a Bluetooth profile.
+ */
+public interface LocalBluetoothProfile {
+
+    /**
+     * Returns true if the user can initiate a connection, false otherwise.
+     */
+    boolean isConnectable();
+
+    /**
+     * Returns true if the user can enable auto connection for this profile.
+     */
+    boolean isAutoConnectable();
+
+    boolean connect(BluetoothDevice device);
+
+    boolean disconnect(BluetoothDevice device);
+
+    int getConnectionStatus(BluetoothDevice device);
+
+    boolean isPreferred(BluetoothDevice device);
+
+    int getPreferred(BluetoothDevice device);
+
+    void setPreferred(BluetoothDevice device, boolean preferred);
+
+    boolean isProfileReady();
+
+    /** Display order for device profile settings. */
+    int getOrdinal();
+
+    /**
+     * Returns the string resource ID for the localized name for this profile.
+     * @param device the Bluetooth device (to distinguish between PAN roles)
+     */
+    int getNameResource(BluetoothDevice device);
+
+    /**
+     * Returns the string resource ID for the summary text for this profile
+     * for the specified device, e.g. "Use for media audio" or
+     * "Connected to media audio".
+     * @param device the device to query for profile connection status
+     * @return a string resource ID for the profile summary text
+     */
+    int getSummaryResourceForDevice(BluetoothDevice device);
+
+    int getDrawableResource(BluetoothClass btClass);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
new file mode 100644
index 0000000..b0a7b27
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothA2dp;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothInputDevice;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothPbap;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelUuid;
+import android.util.Log;
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.List;
+
+/**
+ * LocalBluetoothProfileManager provides access to the LocalBluetoothProfile
+ * objects for the available Bluetooth profiles.
+ */
+public final class LocalBluetoothProfileManager {
+    private static final String TAG = "LocalBluetoothProfileManager";
+    private static final boolean DEBUG = Utils.D;
+    /** Singleton instance. */
+    private static LocalBluetoothProfileManager sInstance;
+
+    /**
+     * An interface for notifying BluetoothHeadset IPC clients when they have
+     * been connected to the BluetoothHeadset service.
+     * Only used by com.android.settings.bluetooth.DockService.
+     */
+    public interface ServiceListener {
+        /**
+         * Called to notify the client when this proxy object has been
+         * connected to the BluetoothHeadset service. Clients must wait for
+         * this callback before making IPC calls on the BluetoothHeadset
+         * service.
+         */
+        void onServiceConnected();
+
+        /**
+         * Called to notify the client that this proxy object has been
+         * disconnected from the BluetoothHeadset service. Clients must not
+         * make IPC calls on the BluetoothHeadset service after this callback.
+         * This callback will currently only occur if the application hosting
+         * the BluetoothHeadset service, but may be called more often in future.
+         */
+        void onServiceDisconnected();
+    }
+
+    private final Context mContext;
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final BluetoothEventManager mEventManager;
+
+    private A2dpProfile mA2dpProfile;
+    private HeadsetProfile mHeadsetProfile;
+    private MapProfile mMapProfile;
+    private final HidProfile mHidProfile;
+    private OppProfile mOppProfile;
+    private final PanProfile mPanProfile;
+    private final PbapServerProfile mPbapProfile;
+
+    /**
+     * Mapping from profile name, e.g. "HEADSET" to profile object.
+     */
+    private final Map<String, LocalBluetoothProfile>
+            mProfileNameMap = new HashMap<String, LocalBluetoothProfile>();
+
+    LocalBluetoothProfileManager(Context context,
+            LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            BluetoothEventManager eventManager) {
+        mContext = context;
+
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mEventManager = eventManager;
+        // pass this reference to adapter and event manager (circular dependency)
+        mLocalAdapter.setProfileManager(this);
+        mEventManager.setProfileManager(this);
+
+        ParcelUuid[] uuids = adapter.getUuids();
+
+        // uuids may be null if Bluetooth is turned off
+        if (uuids != null) {
+            updateLocalProfiles(uuids);
+        }
+
+        // Always add HID and PAN profiles
+        mHidProfile = new HidProfile(context, mLocalAdapter, mDeviceManager, this);
+        addProfile(mHidProfile, HidProfile.NAME,
+                BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED);
+
+        mPanProfile = new PanProfile(context);
+        addPanProfile(mPanProfile, PanProfile.NAME,
+                BluetoothPan.ACTION_CONNECTION_STATE_CHANGED);
+
+        if(DEBUG) Log.d(TAG, "Adding local MAP profile");
+        mMapProfile = new MapProfile(mContext, mLocalAdapter,
+                mDeviceManager, this);
+        addProfile(mMapProfile, MapProfile.NAME,
+                BluetoothMap.ACTION_CONNECTION_STATE_CHANGED);
+
+       //Create PBAP server profile, but do not add it to list of profiles
+       // as we do not need to monitor the profile as part of profile list
+        mPbapProfile = new PbapServerProfile(context);
+
+        if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete");
+    }
+
+    /**
+     * Initialize or update the local profile objects. If a UUID was previously
+     * present but has been removed, we print a warning but don't remove the
+     * profile object as it might be referenced elsewhere, or the UUID might
+     * come back and we don't want multiple copies of the profile objects.
+     * @param uuids
+     */
+    void updateLocalProfiles(ParcelUuid[] uuids) {
+        // A2DP
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) {
+            if (mA2dpProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local A2DP profile");
+                mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this);
+                addProfile(mA2dpProfile, A2dpProfile.NAME,
+                        BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mA2dpProfile != null) {
+            Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing.");
+        }
+
+        // Headset / Handsfree
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) ||
+            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) {
+            if (mHeadsetProfile == null) {
+                if (DEBUG) Log.d(TAG, "Adding local HEADSET profile");
+                mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter,
+                        mDeviceManager, this);
+                addProfile(mHeadsetProfile, HeadsetProfile.NAME,
+                        BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
+            }
+        } else if (mHeadsetProfile != null) {
+            Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing.");
+        }
+
+        // OPP
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) {
+            if (mOppProfile == null) {
+                if(DEBUG) Log.d(TAG, "Adding local OPP profile");
+                mOppProfile = new OppProfile();
+                // Note: no event handler for OPP, only name map.
+                mProfileNameMap.put(OppProfile.NAME, mOppProfile);
+            }
+        } else if (mOppProfile != null) {
+            Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing.");
+        }
+        mEventManager.registerProfileIntentReceiver();
+
+        // There is no local SDP record for HID and Settings app doesn't control PBAP
+    }
+
+    private final Collection<ServiceListener> mServiceListeners =
+            new ArrayList<ServiceListener>();
+
+    private void addProfile(LocalBluetoothProfile profile,
+            String profileName, String stateChangedAction) {
+        mEventManager.addProfileHandler(stateChangedAction, new StateChangedHandler(profile));
+        mProfileNameMap.put(profileName, profile);
+    }
+
+    private void addPanProfile(LocalBluetoothProfile profile,
+            String profileName, String stateChangedAction) {
+        mEventManager.addProfileHandler(stateChangedAction,
+                new PanStateChangedHandler(profile));
+        mProfileNameMap.put(profileName, profile);
+    }
+
+    public LocalBluetoothProfile getProfileByName(String name) {
+        return mProfileNameMap.get(name);
+    }
+
+    // Called from LocalBluetoothAdapter when state changes to ON
+    void setBluetoothStateOn() {
+        ParcelUuid[] uuids = mLocalAdapter.getUuids();
+        if (uuids != null) {
+            updateLocalProfiles(uuids);
+        }
+        mEventManager.readPairedDevices();
+    }
+
+    /**
+     * Generic handler for connection state change events for the specified profile.
+     */
+    private class StateChangedHandler implements BluetoothEventManager.Handler {
+        final LocalBluetoothProfile mProfile;
+
+        StateChangedHandler(LocalBluetoothProfile profile) {
+            mProfile = profile;
+        }
+
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice == null) {
+                Log.w(TAG, "StateChangedHandler found new device: " + device);
+                cachedDevice = mDeviceManager.addDevice(mLocalAdapter,
+                        LocalBluetoothProfileManager.this, device);
+            }
+            int newState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
+            int oldState = intent.getIntExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, 0);
+            if (newState == BluetoothProfile.STATE_DISCONNECTED &&
+                    oldState == BluetoothProfile.STATE_CONNECTING) {
+                Log.i(TAG, "Failed to connect " + mProfile + " device");
+            }
+
+            cachedDevice.onProfileStateChanged(mProfile, newState);
+            cachedDevice.refresh();
+        }
+    }
+
+    /** State change handler for NAP and PANU profiles. */
+    private class PanStateChangedHandler extends StateChangedHandler {
+
+        PanStateChangedHandler(LocalBluetoothProfile profile) {
+            super(profile);
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent, BluetoothDevice device) {
+            PanProfile panProfile = (PanProfile) mProfile;
+            int role = intent.getIntExtra(BluetoothPan.EXTRA_LOCAL_ROLE, 0);
+            panProfile.setLocalRole(device, role);
+            super.onReceive(context, intent, device);
+        }
+    }
+
+    // called from DockService
+    public void addServiceListener(ServiceListener l) {
+        mServiceListeners.add(l);
+    }
+
+    // called from DockService
+    public void removeServiceListener(ServiceListener l) {
+        mServiceListeners.remove(l);
+    }
+
+    // not synchronized: use only from UI thread! (TODO: verify)
+    void callServiceConnectedListeners() {
+        for (ServiceListener l : mServiceListeners) {
+            l.onServiceConnected();
+        }
+    }
+
+    // not synchronized: use only from UI thread! (TODO: verify)
+    void callServiceDisconnectedListeners() {
+        for (ServiceListener listener : mServiceListeners) {
+            listener.onServiceDisconnected();
+        }
+    }
+
+    // This is called by DockService, so check Headset and A2DP.
+    public synchronized boolean isManagerReady() {
+        // Getting just the headset profile is fine for now. Will need to deal with A2DP
+        // and others if they aren't always in a ready state.
+        LocalBluetoothProfile profile = mHeadsetProfile;
+        if (profile != null) {
+            return profile.isProfileReady();
+        }
+        profile = mA2dpProfile;
+        if (profile != null) {
+            return profile.isProfileReady();
+        }
+        return false;
+    }
+
+    public A2dpProfile getA2dpProfile() {
+        return mA2dpProfile;
+    }
+
+    public HeadsetProfile getHeadsetProfile() {
+        return mHeadsetProfile;
+    }
+
+    public PbapServerProfile getPbapProfile(){
+        return mPbapProfile;
+    }
+
+    public MapProfile getMapProfile(){
+        return mMapProfile;
+    }
+
+    /**
+     * Fill in a list of LocalBluetoothProfile objects that are supported by
+     * the local device and the remote device.
+     *
+     * @param uuids of the remote device
+     * @param localUuids UUIDs of the local device
+     * @param profiles The list of profiles to fill
+     * @param removedProfiles list of profiles that were removed
+     */
+    synchronized void updateProfiles(ParcelUuid[] uuids, ParcelUuid[] localUuids,
+            Collection<LocalBluetoothProfile> profiles,
+            Collection<LocalBluetoothProfile> removedProfiles,
+            boolean isPanNapConnected, BluetoothDevice device) {
+        // Copy previous profile list into removedProfiles
+        removedProfiles.clear();
+        removedProfiles.addAll(profiles);
+        profiles.clear();
+
+        if (uuids == null) {
+            return;
+        }
+
+        if (mHeadsetProfile != null) {
+            if ((BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.HSP_AG) &&
+                    BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP)) ||
+                    (BluetoothUuid.isUuidPresent(localUuids, BluetoothUuid.Handsfree_AG) &&
+                            BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree))) {
+                profiles.add(mHeadsetProfile);
+                removedProfiles.remove(mHeadsetProfile);
+            }
+        }
+
+        if (BluetoothUuid.containsAnyUuid(uuids, A2dpProfile.SINK_UUIDS) &&
+            mA2dpProfile != null) {
+            profiles.add(mA2dpProfile);
+            removedProfiles.remove(mA2dpProfile);
+        }
+
+        if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush) &&
+            mOppProfile != null) {
+            profiles.add(mOppProfile);
+            removedProfiles.remove(mOppProfile);
+        }
+
+        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hid) ||
+             BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Hogp)) &&
+            mHidProfile != null) {
+            profiles.add(mHidProfile);
+            removedProfiles.remove(mHidProfile);
+        }
+
+        if(isPanNapConnected)
+            if(DEBUG) Log.d(TAG, "Valid PAN-NAP connection exists.");
+        if ((BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.NAP) &&
+            mPanProfile != null) || isPanNapConnected) {
+            profiles.add(mPanProfile);
+            removedProfiles.remove(mPanProfile);
+        }
+
+        if ((mMapProfile != null) &&
+            (mMapProfile.getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED)) {
+            profiles.add(mMapProfile);
+            removedProfiles.remove(mMapProfile);
+            mMapProfile.setPreferred(device, true);
+        }
+    }
+
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
new file mode 100644
index 0000000..e6a152f
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/MapProfile.java
@@ -0,0 +1,213 @@
+/*
+ * 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.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothMap;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * MapProfile handles Bluetooth MAP profile.
+ */
+public final class MapProfile implements LocalBluetoothProfile {
+    private static final String TAG = "MapProfile";
+    private static boolean V = true;
+
+    private BluetoothMap mService;
+    private boolean mIsProfileReady;
+
+    private final LocalBluetoothAdapter mLocalAdapter;
+    private final CachedBluetoothDeviceManager mDeviceManager;
+    private final LocalBluetoothProfileManager mProfileManager;
+
+    static final ParcelUuid[] UUIDS = {
+        BluetoothUuid.MAP,
+        BluetoothUuid.MNS,
+        BluetoothUuid.MAS,
+    };
+
+    static final String NAME = "MAP";
+
+    // Order of this profile in device profiles list
+
+    // These callbacks run on the main thread.
+    private final class MapServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothMap) proxy;
+            // We just bound to the service, so refresh the UI for any connected MAP devices.
+            List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+            while (!deviceList.isEmpty()) {
+                BluetoothDevice nextDevice = deviceList.remove(0);
+                CachedBluetoothDevice device = mDeviceManager.findDevice(nextDevice);
+                // we may add a new device here, but generally this should not happen
+                if (device == null) {
+                    Log.w(TAG, "MapProfile found new device: " + nextDevice);
+                    device = mDeviceManager.addDevice(mLocalAdapter, mProfileManager, nextDevice);
+                }
+                device.onProfileStateChanged(MapProfile.this,
+                        BluetoothProfile.STATE_CONNECTED);
+                device.refresh();
+            }
+
+            mProfileManager.callServiceConnectedListeners();
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mProfileManager.callServiceDisconnectedListeners();
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        if(V) Log.d(TAG,"isProfileReady(): "+ mIsProfileReady);
+        return mIsProfileReady;
+    }
+
+    MapProfile(Context context, LocalBluetoothAdapter adapter,
+            CachedBluetoothDeviceManager deviceManager,
+            LocalBluetoothProfileManager profileManager) {
+        mLocalAdapter = adapter;
+        mDeviceManager = deviceManager;
+        mProfileManager = profileManager;
+        mLocalAdapter.getProfileProxy(context, new MapServiceListener(),
+                BluetoothProfile.MAP);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return true;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if(V)Log.d(TAG,"connect() - should not get called");
+        return false; // MAP never connects out
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if (!deviceList.isEmpty() && deviceList.get(0).equals(device)) {
+            if (mService.getPriority(device) > BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+            return mService.disconnect(device);
+        } else {
+            return false;
+        }
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.STATE_DISCONNECTED;
+        List<BluetoothDevice> deviceList = mService.getConnectedDevices();
+        if(V) Log.d(TAG,"getConnectionStatus: status is: "+ mService.getConnectionState(device));
+
+        return !deviceList.isEmpty() && deviceList.get(0).equals(device)
+                ? mService.getConnectionState(device)
+                : BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.getPriority(device) > BluetoothProfile.PRIORITY_OFF;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        if (mService == null) return BluetoothProfile.PRIORITY_OFF;
+        return mService.getPriority(device);
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        if (mService == null) return;
+        if (preferred) {
+            if (mService.getPriority(device) < BluetoothProfile.PRIORITY_ON) {
+                mService.setPriority(device, BluetoothProfile.PRIORITY_ON);
+            }
+        } else {
+            mService.setPriority(device, BluetoothProfile.PRIORITY_OFF);
+        }
+    }
+
+    public List<BluetoothDevice> getConnectedDevices() {
+        if (mService == null) return new ArrayList<BluetoothDevice>(0);
+        return mService.getDevicesMatchingConnectionStates(
+              new int[] {BluetoothProfile.STATE_CONNECTED,
+                         BluetoothProfile.STATE_CONNECTING,
+                         BluetoothProfile.STATE_DISCONNECTING});
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return BluetoothProfile.MAP;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_map;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_map_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                return R.string.bluetooth_map_profile_summary_connected;
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.MAP,
+                                                                       mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up MAP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
new file mode 100755
index 0000000..31e675c
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import com.android.settingslib.R;
+
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+
+/**
+ * OppProfile handles Bluetooth OPP.
+ */
+final class OppProfile implements LocalBluetoothProfile {
+
+    static final String NAME = "OPP";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 2;
+
+    public boolean isConnectable() {
+        return false;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        return false;
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        return BluetoothProfile.STATE_DISCONNECTED; // Settings app doesn't handle OPP
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return BluetoothProfile.PRIORITY_OFF; // Settings app doesn't handle OPP
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+    }
+
+    public boolean isProfileReady() {
+        return true;
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_opp;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return 0;   // OPP profile not displayed in UI
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return 0;   // no icon for OPP
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
new file mode 100755
index 0000000..3af89e6
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PanProfile.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPan;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * PanProfile handles Bluetooth PAN profile (NAP and PANU).
+ */
+final class PanProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PanProfile";
+    private static boolean V = true;
+
+    private BluetoothPan mService;
+    private boolean mIsProfileReady;
+
+    // Tethering direction for each device
+    private final HashMap<BluetoothDevice, Integer> mDeviceRoleMap =
+            new HashMap<BluetoothDevice, Integer>();
+
+    static final String NAME = "PAN";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 4;
+
+    // These callbacks run on the main thread.
+    private final class PanServiceListener
+            implements BluetoothProfile.ServiceListener {
+
+        public void onServiceConnected(int profile, BluetoothProfile proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothPan) proxy;
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected(int profile) {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PanProfile(Context context) {
+        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+        adapter.getProfileProxy(context, new PanServiceListener(),
+                BluetoothProfile.PAN);
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        if (mService == null) return false;
+        List<BluetoothDevice> sinks = mService.getConnectedDevices();
+        if (sinks != null) {
+            for (BluetoothDevice sink : sinks) {
+                mService.disconnect(sink);
+            }
+        }
+        return mService.connect(device);
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect(device);
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        return mService.getConnectionState(device);
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        // return current connection status so profile checkbox is set correctly
+        return getConnectionStatus(device) == BluetoothProfile.STATE_CONNECTED;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return -1;
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        // ignore: isPreferred is always true for PAN
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        if (isLocalRoleNap(device)) {
+            return R.string.bluetooth_profile_pan_nap;
+        } else {
+            return R.string.bluetooth_profile_pan;
+        }
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        int state = getConnectionStatus(device);
+        switch (state) {
+            case BluetoothProfile.STATE_DISCONNECTED:
+                return R.string.bluetooth_pan_profile_summary_use_for;
+
+            case BluetoothProfile.STATE_CONNECTED:
+                if (isLocalRoleNap(device)) {
+                    return R.string.bluetooth_pan_nap_profile_summary_connected;
+                } else {
+                    return R.string.bluetooth_pan_user_profile_summary_connected;
+                }
+
+            default:
+                return Utils.getConnectionStateSummary(state);
+        }
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_network_pan;
+    }
+
+    // Tethering direction determines UI strings.
+    void setLocalRole(BluetoothDevice device, int role) {
+        mDeviceRoleMap.put(device, role);
+    }
+
+    boolean isLocalRoleNap(BluetoothDevice device) {
+        if (mDeviceRoleMap.containsKey(device)) {
+            return mDeviceRoleMap.get(device) == BluetoothPan.LOCAL_NAP_ROLE;
+        } else {
+            return false;
+        }
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                BluetoothAdapter.getDefaultAdapter().closeProfileProxy(BluetoothProfile.PAN, mService);
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PAN proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
new file mode 100755
index 0000000..a552b24a
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapServerProfile.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothClass;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothPbap;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.BluetoothUuid;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import com.android.settingslib.R;
+
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * PBAPServer Profile
+ */
+public final class PbapServerProfile implements LocalBluetoothProfile {
+    private static final String TAG = "PbapServerProfile";
+    private static boolean V = true;
+
+    private BluetoothPbap mService;
+    private boolean mIsProfileReady;
+
+    static final String NAME = "PBAP Server";
+
+    // Order of this profile in device profiles list
+    private static final int ORDINAL = 6;
+
+    // The UUIDs indicate that remote device might access pbap server
+    static final ParcelUuid[] PBAB_CLIENT_UUIDS = {
+        BluetoothUuid.HSP,
+        BluetoothUuid.Handsfree,
+        BluetoothUuid.PBAP_PCE
+    };
+
+    // These callbacks run on the main thread.
+    private final class PbapServiceListener
+            implements BluetoothPbap.ServiceListener {
+
+        public void onServiceConnected(BluetoothPbap proxy) {
+            if (V) Log.d(TAG,"Bluetooth service connected");
+            mService = (BluetoothPbap) proxy;
+            mIsProfileReady=true;
+        }
+
+        public void onServiceDisconnected() {
+            if (V) Log.d(TAG,"Bluetooth service disconnected");
+            mIsProfileReady=false;
+        }
+    }
+
+    public boolean isProfileReady() {
+        return mIsProfileReady;
+    }
+
+    PbapServerProfile(Context context) {
+        BluetoothPbap pbap = new BluetoothPbap(context, new PbapServiceListener());
+    }
+
+    public boolean isConnectable() {
+        return true;
+    }
+
+    public boolean isAutoConnectable() {
+        return false;
+    }
+
+    public boolean connect(BluetoothDevice device) {
+        /*Can't connect from server */
+        return false;
+
+    }
+
+    public boolean disconnect(BluetoothDevice device) {
+        if (mService == null) return false;
+        return mService.disconnect();
+    }
+
+    public int getConnectionStatus(BluetoothDevice device) {
+        if (mService == null) {
+            return BluetoothProfile.STATE_DISCONNECTED;
+        }
+        if (mService.isConnected(device))
+            return BluetoothProfile.STATE_CONNECTED;
+        else
+            return BluetoothProfile.STATE_DISCONNECTED;
+    }
+
+    public boolean isPreferred(BluetoothDevice device) {
+        return false;
+    }
+
+    public int getPreferred(BluetoothDevice device) {
+        return -1;
+    }
+
+    public void setPreferred(BluetoothDevice device, boolean preferred) {
+        // ignore: isPreferred is always true for PBAP
+    }
+
+    public String toString() {
+        return NAME;
+    }
+
+    public int getOrdinal() {
+        return ORDINAL;
+    }
+
+    public int getNameResource(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap;
+    }
+
+    public int getSummaryResourceForDevice(BluetoothDevice device) {
+        return R.string.bluetooth_profile_pbap_summary;
+    }
+
+    public int getDrawableResource(BluetoothClass btClass) {
+        return R.drawable.ic_bt_cellphone;
+    }
+
+    protected void finalize() {
+        if (V) Log.d(TAG, "finalize()");
+        if (mService != null) {
+            try {
+                mService.close();
+                mService = null;
+            }catch (Throwable t) {
+                Log.w(TAG, "Error cleaning up PBAP proxy", t);
+            }
+        }
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
new file mode 100644
index 0000000..c919426
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/Utils.java
@@ -0,0 +1,43 @@
+package com.android.settingslib.bluetooth;
+
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.R;
+
+public class Utils {
+    public static final boolean V = false; // verbose logging
+    public static final boolean D = true;  // regular logging
+
+    private static ErrorListener sErrorListener;
+
+    public static int getConnectionStateSummary(int connectionState) {
+        switch (connectionState) {
+        case BluetoothProfile.STATE_CONNECTED:
+            return R.string.bluetooth_connected;
+        case BluetoothProfile.STATE_CONNECTING:
+            return R.string.bluetooth_connecting;
+        case BluetoothProfile.STATE_DISCONNECTED:
+            return R.string.bluetooth_disconnected;
+        case BluetoothProfile.STATE_DISCONNECTING:
+            return R.string.bluetooth_disconnecting;
+        default:
+            return 0;
+        }
+    }
+
+    static void showError(Context context, String name, int messageResId) {
+        if (sErrorListener != null) {
+            sErrorListener.onShowError(context, name, messageResId);
+        }
+    }
+
+    public static void setErrorListener(ErrorListener listener) {
+        sErrorListener = listener;
+    }
+
+    public interface ErrorListener {
+        void onShowError(Context context, String name, int messageResId);
+    }
+
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 78f6ace..eac83d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -32,14 +32,18 @@
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.internal.widget.LockPatternUtils;
+
 import libcore.io.IoUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.CharArrayReader;
 import java.io.DataInputStream;
@@ -76,10 +80,11 @@
     private static final String KEY_SECURE = "secure";
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
+    private static final String KEY_LOCK_SETTINGS = "lock_settings";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 3;
+    private static final int STATE_VERSION = 4;
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
@@ -89,20 +94,23 @@
     private static final int STATE_WIFI_SUPPLICANT = 3;
     private static final int STATE_WIFI_CONFIG     = 4;
     private static final int STATE_GLOBAL          = 5;
+    private static final int STATE_LOCK_SETTINGS   = 6;
 
-    private static final int STATE_SIZE            = 6; // The current number of state items
+    private static final int STATE_SIZE            = 7; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
         0,
         4,              // version 1
         5,              // version 2 added STATE_WIFI_CONFIG
-        STATE_SIZE      // version 3 added STATE_GLOBAL
+        6,              // version 3 added STATE_GLOBAL
+        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
     };
 
     // Versioning of the 'full backup' format
-    private static final int FULL_BACKUP_VERSION = 2;
+    private static final int FULL_BACKUP_VERSION = 3;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
+    private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -124,6 +132,10 @@
     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
     private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
 
+    // Keys within the lock settings section
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
+
     // Name of the temporary file we use during full backup/restore.  This is
     // stored in the full-backup tarfile as well, so should not be changed.
     private static final String STAGE_FILE = "flattened-data";
@@ -367,6 +379,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -387,6 +400,9 @@
         stateChecksums[STATE_WIFI_CONFIG] =
             writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
                     data);
+        stateChecksums[STATE_LOCK_SETTINGS] =
+            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                    lockSettingsData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -492,6 +508,8 @@
             } else if (KEY_WIFI_CONFIG.equals(key)) {
                 initWifiRestoreIfNecessary();
                 mWifiRestore.incorporateWifiConfigFile(data);
+            } else if (KEY_LOCK_SETTINGS.equals(key)) {
+                restoreLockSettings(data);
              } else {
                 data.skipEntityData();
             }
@@ -513,6 +531,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -547,6 +566,9 @@
             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
             out.writeInt(wifiConfigData.length);
             out.write(wifiConfigData);
+            if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
+            out.writeInt(lockSettingsData.length);
+            out.write(lockSettingsData);
 
             out.flush();    // also flushes downstream
 
@@ -629,6 +651,16 @@
             in.readFully(buffer, 0, nBytes);
             restoreFileData(mWifiConfigFile, buffer, nBytes);
 
+            if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreLockSettings(buffer, nBytes);
+                }
+            }
+
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -676,6 +708,9 @@
             return oldChecksum;
         }
         try {
+            if (DEBUG_BACKUP) {
+                Log.v(TAG, "Writing entity " + key + " of size " + data.length);
+            }
             output.writeEntityHeader(key, data.length);
             output.writeEntityData(data, data.length);
         } catch (IOException ioe) {
@@ -714,6 +749,31 @@
         }
     }
 
+    /**
+     * Serialize the owner info settings
+     */
+    private byte[] getLockSettings() {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+        final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled();
+        final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        try {
+            out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
+            out.writeUTF(ownerInfoEnabled ? "1" : "0");
+            if (ownerInfo != null) {
+                out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
+                out.writeUTF(ownerInfo != null ? ownerInfo : "");
+            }
+            // End marker
+            out.writeUTF("");
+            out.flush();
+        } catch (IOException ioe) {
+        }
+        return baos.toByteArray();
+    }
+
     private void restoreSettings(BackupDataInput data, Uri contentUri,
             HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
@@ -797,6 +857,50 @@
     }
 
     /**
+     * Restores the owner info enabled and owner info settings in LockSettings.
+     *
+     * @param buffer
+     * @param nBytes
+     */
+    private void restoreLockSettings(byte[] buffer, int nBytes) {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
+        DataInputStream in = new DataInputStream(bais);
+        try {
+            String key;
+            // Read until empty string marker
+            while ((key = in.readUTF()).length() > 0) {
+                final String value = in.readUTF();
+                if (DEBUG_BACKUP) {
+                    Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
+                }
+                switch (key) {
+                    case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
+                        lockPatternUtils.setOwnerInfoEnabled("1".equals(value));
+                        break;
+                    case KEY_LOCK_SETTINGS_OWNER_INFO:
+                        lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
+                        break;
+                }
+            }
+            in.close();
+        } catch (IOException ioe) {
+        }
+    }
+
+    private void restoreLockSettings(BackupDataInput data) {
+        final byte[] settings = new byte[data.getDataSize()];
+        try {
+            data.readEntityData(settings, 0, settings.length);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Couldn't read entity data");
+            return;
+        }
+        restoreLockSettings(settings, settings.length);
+    }
+
+    /**
      * Given a cursor and a set of keys, extract the required keys and
      * values and write them to a byte array.
      *
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1d8cb46..f7bbce0 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -79,7 +79,8 @@
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
-            android:layout_marginBottom="@dimen/close_handle_underlap" />
+            android:layout_marginBottom="@dimen/close_handle_underlap"
+            android:importantForAccessibility="no" />
 
         <ViewStub
             android:id="@+id/keyguard_user_switcher"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 45f4290..81285ee 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ontsluit"</string>
     <string name="phone_label" msgid="2320074140205331708">"maak foon oop"</string>
     <string name="camera_label" msgid="7261107956054836961">"maak kamera oop"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knoppie vir wissel van invoermetode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Versoenbaarheid-zoem se knoppie."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoem kleiner na groter skerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth gekoppel."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiele warmkol aangeskakel."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Uitsaai van skerm gestaak."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skermhelderheid"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G-data is af"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data is af"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Sellulêre data is af"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is af"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Jou toestel het data afgeskakel, want dit het die limiet bereik wat jy gestel het.\n\nAs dit weer aangeskakel word, kan dit tot heffings van jou diensverskaffer af lei."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Skakel data aan"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data is laat wag"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data is laat wag"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sellulêre data is laat wag"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is laat wag"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat die dataperk wat gestel is, bereik is, het die toestel datagebruik vir die res van hierdie siklus laat wag.\n\nAs dit hervat word, kan dit tot heffings deur jou diensverskaffer lei."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding nie"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi gekoppel"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Soek vir GPS"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index aac7a2f..3248d7a 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ክፈት"</string>
     <string name="phone_label" msgid="2320074140205331708">"ስልክ ክፈት"</string>
     <string name="camera_label" msgid="7261107956054836961">"ካሜራ ክፈት"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"የግቤት ስልት አዝራር ቀይር"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"የተኳኋኝአጉላ አዝራር።"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"አነስተኛውን ማያ ወደ ትልቅ አጉላ።"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ብሉቱዝ ተያይዟል።"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"የተንቀሳቃሽ ስልክ መገናኛ ነጥብ በርቷል።"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ማያ ገጽ መውሰድ ቆሟል።"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ብሩህነት ያሳዩ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2ጂ-3ጂ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4ጂ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"የተንቀሳቃሽ ስልክ ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ውሂብ ጠፍቷል"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"መሳሪያዎ እርስዎ ያዘጋጁት ገደብ ላይ ስለደረሰ ውሂብን አጥፍቷል።\n\nመልሰው ማብራት ከአገልግሎት አቅራቢዎ ክፍያዎችን ሊያስከትል ይችላል።"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ውሂብ ያብሩ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2ጂ-3ጂ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4ጂ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"የተንቀሳቃሽ ስልክ ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ውሂብ ላፍታ ቆሟል"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"የእርስዎ የተዋቀረው የውሂብ ገደብ ላይ ስለተደረሰ፣ የዚህን ዑደት አጠቃቀም ለማስታወስ መሣሪያው ላፍታ ቆሟል።\n\nከቆመበት ማስቀጠሉ ከእርስዎ የአገልግሎት አቅራቢ ክፍያን ሊያስጠይቅዎት ይችላል።"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ከቆመበት ቀጥል"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ምንም በይነመረብ ተያያዥ የለም።"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ተያይዟል"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ለGPS በመፈለግ ላይ"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 447196a..6379288 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -92,7 +92,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"إلغاء القفل"</string>
     <string name="phone_label" msgid="2320074140205331708">"فتح الهاتف"</string>
     <string name="camera_label" msgid="7261107956054836961">"فتح الكاميرا"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"زر تبديل طريقة الإدخال."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"زر تكبير/تصغير للتوافق."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"استخدام التكبير/التصغير لتحويل شاشة صغيرة إلى شاشة أكبر"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"تم توصيل البلوتوث."</string>
@@ -205,12 +204,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"تم تشغيل نقطة اتصال الجوّال."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"توقف إرسال الشاشة."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"سطوع الشاشة"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2-3 غيغابايت من البيانات المعطلة"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4 غيغابايت من البيانات المعطلة"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"البيانات الخلوية معطلة"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"البيانات معطلة"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"عطل جهازك البيانات نظرًا لبلوغها الحد الذي تم تعيينه.\n\nعلمًا بأن إعادتها قد يؤدي إلى تحمل رسوم من قبل مشغّل شبكة الجوّال."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"تشغيل البيانات"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"بيانات شبكات الجيل الثاني والثالث متوقفة مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"تم إيقاف بيانات شبكة الجيل الرابع مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"تم إيقاف بيانات شبكة الجوّال مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"تم إيقاف البيانات مؤقتًا"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"نظرًا لأنك بلغت الحد الأقصى المحدد للبيانات، فقد أوقف الجهاز استخدام البيانات مؤقتًا في بقية هذه الدورة.\n\nومن الممكن أن يؤدي الاستئناف إلى تحصيل رسوم من قِبل مشغِّل شبكة الجوّال."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"استئناف"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"لا يوجد اتصال إنترنت"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏جارٍ البحث عن GPS"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a058c39..6212b3f 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"отключване"</string>
     <string name="phone_label" msgid="2320074140205331708">"отваряне на телефона"</string>
     <string name="camera_label" msgid="7261107956054836961">"отваряне на камерата"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Бутон за превключване на метода на въвеждане."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Бутон за промяна на мащаба с цел съвместимост."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Промяна на мащаба на екрана от по-малък до по-голям."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е включен."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка за достъп се включи."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Предаването на съдържанието от екрана спря."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркост на екрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Данните от 2G – 3G са изключени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Данните от 4G са изключени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилните данни са изключени"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Данните са изключени"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Устройството ви изключи данните, защото зададеното от вас ограничение бе достигнато.\n\nПовторното им включване може да доведе до таксуване от оператора ви."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Включване на данните"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Данните от 2G – 3G са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Данните от 4G са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните данни са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Данните са поставени на пауза"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Тъй като зададеното от вас ограничение за данни бе достигнато, устройството постави преноса им на пауза за остатъка от този цикъл.\n\nВъзобновяването може да доведе до таксуване от оператора ви."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Възобновяване"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Няма връзка с интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: Има връзка"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Търси се GPS"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 8805acf..a6fc71f 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"আনলক করুন"</string>
     <string name="phone_label" msgid="2320074140205331708">"ফোন খুলুন"</string>
     <string name="camera_label" msgid="7261107956054836961">"ক্যামেরা খুলুন"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ইনপুট পদ্ধতির বোতাম পরিবর্তন করুন৷"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"সামঞ্জস্যের জুম বোতাম৷"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ছোট থেকে বৃহৎ স্ক্রীণে জুম করুন৷"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth সংযুক্ত হয়েছে৷"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"মোবাইল হটস্পট চালু হয়েছে।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"স্ক্রীন কাস্ট করা থেমেছে।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"প্রদর্শনের উজ্জ্বলতা"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"সেলুলার ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ডেটা বন্ধ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"আপনার সেট করা ডেটা সীমায় পৌঁছে যাওয়ায় আপনার ডিভাইসটি ডেটা বন্ধ করে দিয়েছে।\n\nএটি চালু করে দিলে আপনাকে পরিষেবা প্রদানকারীর করা চার্জ বহন করতে হতে পারে।"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ডেটা চালু করুন"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"সেলুলার ডেটা বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ডেট বিরতি দেওয়া হয়েছে"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"আপনার সেট ডেটার সীমা অবধি পৌঁছনোর কারনে ডিভাইস এই চক্রের অবশিষ্টাংশের জন্য ডেটা ব্যবহারে বিরতি দেওয়া হয়েছে৷ \n\nপুনরায় চালু করা হলে পরিষেবা প্রদানকারীর দ্বারা চার্জের করা হতে পারে৷"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"পুনঃসূচনা করুন"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"কোনো ইন্টারনেট সংযোগ নেই"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi সংযুক্ত হয়েছে"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS এর জন্য অনুসন্ধান করা হচ্ছে"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 1b9987c..d48be7e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloqueja"</string>
     <string name="phone_label" msgid="2320074140205331708">"obre el telèfon"</string>
     <string name="camera_label" msgid="7261107956054836961">"obre la càmera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botó de canvi del mètode d\'entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botó de zoom de compatibilitat."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Amplia menys com més gran sigui la pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connectat."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"El punt d\'accés mòbil està activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"S\'ha aturat l\'emissió de la pantalla."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillantor de la pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"L\'ús de dades 2G-3G està desactivat"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"L\'ús de dades 4G està desactivat"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Les dades mòbils estan desactivades"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Les dades estan desactivades"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"S\'han desactivat les dades del dispositiu perquè ha arribat al límit que has definit.\n\nSi les tornes a activar, l\'operador de telefonia mòbil et pot aplicar càrrecs."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activa les dades"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Les dades 2G-3G estan aturades"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Les dades 4G estan aturades"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Les dades mòbils estan aturades"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Les dades estan aturades"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Com que has arribat al límit de dades establert, s\'ha aturat l\'ús de dades del dispositiu per a la resta d\'aquest cicle.\n\nSi el reprens, l\'operador de telefonia mòbil pot aplicar càrrecs."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprèn"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No hi ha connexió a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: connectada"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"S\'està cercant un GPS"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index c5ee2fb..8c7428b 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odemknout"</string>
     <string name="phone_label" msgid="2320074140205331708">"otevřít telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"spustit fotoaparát"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačítko přepnutí metody zadávání"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačítko úpravy velikosti z důvodu kompatibility"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zvětšit menší obrázek na větší obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Rozhraní Bluetooth je připojeno."</string>
@@ -205,12 +204,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Odesílání obrazovky zastaveno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeje"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G a 3G jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilní data jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data jsou vypnuta"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Zařízení datové přenosy vypnulo, protože dosáhlo limitu, který jste nastavili.\n\nJejich opětovné zapnutí může vézt k účtování poplatků operátorem."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Zapnout data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G a 3G jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilní data jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data jsou pozastavena"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Protože jste dosáhli nastaveného limitu dat, zařízení využití dat pro zbytek tohoto cyklu pozastavilo.\n\nObnovení může vést k poplatkům od operátora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Pokračovat"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Žádné přip. k internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: připojeno"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhledávání satelitů GPS"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 11f1640..ff21bc9 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås op"</string>
     <string name="phone_label" msgid="2320074140205331708">"åbn telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"åbn kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Skift indtastningsmetode-knappen."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knap for kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom mindre til større skærm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tilsluttet."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilhotspot er slået til."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casting af din skærm er stoppet."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skærmens lysstyrke"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G-data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildata er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data er deaktiveret"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Enheden har deaktiveret data, fordi den grænse, du har angivet, er nået.\n\nHvis du aktiverer dataforbrug igen, kan mobilselskabet pålægge gebyrer."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktivér data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G-data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er sat på pause"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er sat på pause"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom din fastsatte datagrænse blev nået, har enheden sat dataforbruget på pause i den resterende del af cyklussen.\n\nHvis du genaktiverer dataforbruget, kan det medføre gebyrer fra dit mobilselskab."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Genoptag"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen internetforb."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi er forbundet"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søger efter GPS"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4bf3076..a5685ee 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"Entsperren"</string>
     <string name="phone_label" msgid="2320074140205331708">"Telefon öffnen"</string>
     <string name="camera_label" msgid="7261107956054836961">"Kamera öffnen"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Schaltfläche zum Ändern der Eingabemethode"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Schaltfläche für Kompatibilitätszoom"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom auf einen größeren Bildschirm"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Mit Bluetooth verbunden"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Der mobile Hotspot ist aktiviert."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Die Bildschirmübertragung wurde angehalten."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helligkeit des Displays"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilfunkdaten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Daten deaktiviert"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Die Datennutzung wurde auf Ihrem Gerät deaktiviert, da das von Ihnen festgelegte Limit erreicht wurde.\n\nWenn Sie die Funktion erneut aktivieren, berechnet Ihr Mobilfunkanbieter möglicherweise Gebühren."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Daten aktivieren"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-/3G-Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilfunkdaten pausiert"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Daten pausiert"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Da Ihr festgelegtes Datenlimit erreicht wurde, hat das Gerät die Datennutzung für den Rest dieses Zeitraums pausiert.\n\nWenn Sie diese fortsetzen, können möglicherweise Kosten bei Ihrem Mobilfunkanbieter entstehen."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Fortsetzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Keine Internetverbindung"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WLAN verbunden"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS wird gesucht..."</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index d5a7b2b..ec61344 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ξεκλείδωμα"</string>
     <string name="phone_label" msgid="2320074140205331708">"άνοιγμα τηλεφώνου"</string>
     <string name="camera_label" msgid="7261107956054836961">"άνοιγμα φωτογραφικής μηχανής"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Κουμπί εναλλαγής μεθόδου εισόδου"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Κουμπί εστίασης συμβατότητας."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Ζουμ από μικρότερη σε μεγαλύτερη οθόνη."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Το Bluetooth είναι συνδεδεμένο."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Το σημείο πρόσβασης κινητής συσκευής ενεργοποιήθηκε."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Η μετάδοση της οθόνης διακόπηκε."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Φωτεινότητα οθόνης"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Τα δεδομένα 2G-3G είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Τα δεδομένα 4G είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Τα δεδομένα κινητής τηλεφωνίας είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Τα δεδομένα είναι ανενεργά"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Τα δεδομένα απενεργοποιήθηκαν στη συσκευή σας, επειδή εξαντλήσατε το όριο που ορίσατε.\n\nΗ επανενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ενεργοποίηση δεδομένων"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Τα δεδομένα 2G-3G τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Τα δεδομένα 4G τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Τα δεδομένα κινητής τηλεφωνίας τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Τα δεδομένα τέθηκαν σε παύση"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Επειδή συμπληρώθηκε το όριο των δεδομένων που ορίστηκε για τη συσκευή σας, η χρήση δεδομένων τέθηκε σε παύση για το υπόλοιπο αυτού του κύκλου.\n\nΗ εκ νέου ενεργοποίησή τους ενδέχεται να επιφέρει χρεώσεις από την εταιρεία κινητής τηλεφωνίας σας."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Συνέχιση"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Χωρ. σύνδ. στο Διαδ."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi συνδεδεμένο"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Αναζήτηση για GPS"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index a7c929b..c6cc776 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"open phone"</string>
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot turned on."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Screen casting stopped."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G data is off"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G data is off"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobile data is off"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is off"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Your device turned off data because it reached the limit you set.\n\nTurning it back on may lead to charges from your operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Turn on data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index a7c929b..c6cc776 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"open phone"</string>
     <string name="camera_label" msgid="7261107956054836961">"open camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Switch input method button."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Compatibility zoom button."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom smaller to larger screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connected."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobile hotspot turned on."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Screen casting stopped."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Display brightness"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G data is off"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G data is off"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobile data is off"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data is off"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Your device turned off data because it reached the limit you set.\n\nTurning it back on may lead to charges from your operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Turn on data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G data is paused"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data is paused"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobile data is paused"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data is paused"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Because your set data limit was reached, the device has paused data usage for the remainder of this cycle.\n\nResuming may lead to charges from your operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Resume"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"No Internet connection"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connected"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Searching for GPS"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index aeef5b7..a04779b 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona móvil activada"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisión de pantalla detenida"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datos 2G-3G desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datos 4G desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datos móviles desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datos desactivados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"El dispositivo desactivó los datos porque alcanzó el límite establecido.\n\nSi los vuelves a activar, podrían aplicarse cargos del proveedor."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Debido que se alcanzó el límite de datos establecido, el dispositivo pausó el uso de datos para el resto de este ciclo.\n\nLa reanudación podría tener como resultado cargos del proveedor."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 39e83a4..a9103a8 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Botón Cambiar método de entrada"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidad"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de pantalla más pequeña a más grande"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Punto de acceso móvil activado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Envío de pantalla detenido."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de la pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datos 2G-3G desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datos 4G desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datos móviles desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Conexión de datos desactivada"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Se ha desactivado la conexión de datos del dispositivo porque se ha alcanzado el límite establecido.\n\nSi se vuelve a activar, se podrían aplicar cargos del operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar conexión de datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Datos 2G-3G pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Datos 4G pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Datos móviles pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datos pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Has alcanzado el límite de datos establecido, por lo que el dispositivo ha pausado el uso de datos para el resto de este ciclo.\n\nSi lo reanudas, el operador puede facturar cargos."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reanudar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sin conexión a Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Con conexión Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index d58bc52..4f891e3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ava lukk"</string>
     <string name="phone_label" msgid="2320074140205331708">"ava telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"ava kaamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Sisestusmeetodi vahetamise nupp."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Sobivussuumi nupp."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Suumi suuremale ekraanile vähem."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth on ühendatud."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiilside leviala on sisse lülitatud."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekraanikuva ülekandmine on peatatud."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekraani heledus"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mob. andmeside väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Andmeside on väljalülitatud"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Seade lülitas andmeside välja, sest teie määratud limiit on täis.\n\nKui lülitate andmeside uuesti sisse, siis võivad lisanduda operaatori tasud."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Lülita andmeside sisse"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilse andmeside kasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Andmekasutus on peatatud"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kuna jõudsite andmemahu määratud piirini, peatas seade andmekasutuse ülejäänud tsükliks.\n\nJätkamisel võivad lisanduda operaatoritasud."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jätka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Interneti-ühendus puudub"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"WiFi on ühendatud"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-i otsimine"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 1753575..3697b05 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desblokeatu"</string>
     <string name="phone_label" msgid="2320074140205331708">"ireki telefonoan"</string>
     <string name="camera_label" msgid="7261107956054836961">"ireki kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Idazketa-metodoa aldatzeko botoia."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoom-bateragarritasunaren botoia."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Handiagotu pantaila txikia."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetootha konektatuta."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Konexioa partekatzeko aukera aktibatu egin da."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Pantaila igortzeari utzi zaio."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bistaratu distira"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datu mugikorrak desaktibatuta daude"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datu-konexioa desaktibatuta dago"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Gailuak datu-konexioa desaktibatu du, ezarritako mugara iritsi delako.\n\nBerriro aktibatuz gero, operadoreak zerbait kobratuko dizu agian."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktibatu datu-konexioa"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Sare mugikorreko datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datuen erabilera eten da"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Zehaztuta duzun datuen erabilera-mugara iritsi zarenez, gailuak datuen erabilera eten du zikloa amaitzen den arte.\n\nDatuak erabiltzen jarraitzen baduzu, gastu gehiago ordaindu beharko dizkiozu agian operadoreari."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jarraitu erabiltzen"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ez duzu Interneteko konexiorik"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi konektatuta"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS seinalearen bila"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index a704494..602d1c2 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"بازکردن قفل"</string>
     <string name="phone_label" msgid="2320074140205331708">"باز کردن تلفن"</string>
     <string name="camera_label" msgid="7261107956054836961">"باز کردن دوربین"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"کلید تغییر روش ورود متن."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"دکمه بزرگنمایی سازگار."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"بزرگنمایی از صفحه‌های کوچک تا بزرگ."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوتوث متصل است."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"نقطه اتصال دستگاه همراه روشن شد."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"فرستادن صفحه نمایش متوقف شد."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"روشنایی نمایشگر"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏داده 2G-3G خاموش است"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏داده 4G خاموش است"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"داده شبکه سلولی خاموش است"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"داده خاموش است"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"دستگاه شما خاموش شد زیرا به حد تنظیم شده توسط شما رسید.\n\nروشن کردن مجدد آن می‌تواند به هزینه‌هایی از طرف شرکت مخابراتی شما منجر شود."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"روشن کردن داده"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏داده 2G-3G موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏داده 4G موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"داده شبکه همراه موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"داده موقتاً متوقف شده است"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چون به محدودیت داده تنظیم شده رسیده‌اید، دستگاه مصرف داده را برای باقیمانده این دوره موقتاً متوقف کرده است.\n\nاگر ادامه دهید شاید موجب کسر هزینه از طرف شرکت مخابراتی شما شود."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"از سر‌گیری"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"اتصال اینترنتی وجود ندارد"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi متصل شد"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏جستجو برای GPS"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4480bda7..4224e30 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"avaa lukitus"</string>
     <string name="phone_label" msgid="2320074140205331708">"avaa puhelin"</string>
     <string name="camera_label" msgid="7261107956054836961">"avaa kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Syöttötavan vaihtopainike."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Yhteensopivuuszoomaus-painike."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoomaa pienemmältä suuremmalle ruudulle."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth yhdistetty."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiiliyhteyden hotspot otettiin käyttöön."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ruudun lähetys pysäytettiin."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Näytön kirkkaus"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G-tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiilitiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Tiedonsiirto ei ole käytössä"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Laitteesi poisti tiedonsiirron käytöstä, koska se saavutti asettamasi rajan.\n\nOperaattorisi saattaa veloittaa sinulta lisämaksuja, jos otat sen uudelleen käyttöön."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ota tiedonsiirto käyttöön"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G-tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiilitiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Tiedonsiirto keskeytettiin"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Määrittämäsi tiedonsiirtorajoitus saavutettiin, ja laite keskeytti tiedonsiirron tämän kauden loppuajaksi.\n\nOperaattorisi voi veloittaa sinulta lisämaksun, jos jatkat tiedonsiirtoa."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Jatka"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ei internetyhteyttä"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi yhdistetty"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Haetaan GPS-yhteyttä"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 49dd20a..b064d0e 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
     <string name="phone_label" msgid="2320074140205331708">"Ouvrir le téléphone"</string>
     <string name="camera_label" msgid="7261107956054836961">"Ouvrir l\'appareil photo"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran arrêtée."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'écran"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Données 2G/3G désactivées"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Données 4G désactivées"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Données cellulaire désactivées"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Votre appareil a désactivé les données, car il a atteint la limite définie.\n\nSi vous les réactivez, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activer les données"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G/3G désactivées"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données cellulaires désactivées"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre fournisseur de services risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reprendre"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 4b3f42a..5af507b 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"déverrouiller"</string>
     <string name="phone_label" msgid="2320074140205331708">"ouvrir le téléphone"</string>
     <string name="camera_label" msgid="7261107956054836961">"ouvrir l\'appareil photo"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bouton \"Changer le mode de saisie\""</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Bouton \"Zoom de compatibilité\""</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilité avec la taille de l\'écran"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth connecté"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Point d\'accès mobile activé."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Diffusion d\'écran interrompue."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosité de l\'affichage"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Données 2G-3G désactivées"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Données 4G désactivées"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Données mobiles désactivées"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Données désactivées"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Votre appareil a désactivé les données, car il a atteint la limite que vous avez définie.\n\nSi vous les réactivez, votre opérateur risque de vous facturer des frais supplémentaires."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activer les données"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Données 2G-3G désactivées"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Données 4G désactivées"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Données mobiles désactivées"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Données désactivées"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Vous avez atteint le quota de données maximal. La consommation des données a donc été interrompue pour la fin de la période de facturation en cours.\n\nSi vous réactivez les données, votre opérateur risque de vous facturer des frais supplémentaires."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Réactiver"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Aucune connexion Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Connecté au Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Recherche de GPS..."</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 350a50f..9b3d62e 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir teléfono"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir cámara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Cambiar o botón do método de entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botón de zoom de compatibilidade"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom de compatibilidade co tamaño da pantalla."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Activouse a zona interactiva móbil."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Detívose a emisión en pantalla."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brillo de pantalla"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os datos 2G-3G están desactivados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os datos 4G están desactivados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os datos móbiles están desactivados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os datos están desactivados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O teu dispositivo desactivou os datos porque alcanzou o límite establecido.\n\nActivalos de novo pode supoñer gastos adicionais do teu operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activar datos"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os datos 2G-3G están en pausa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os datos 4G están en pausa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os datos de móbiles están en pausa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os datos están en pausa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como acadaches o límite de datos definido, o dispositivo puxo en pausa o uso de datos para o resto do ciclo.\n\nSe retomas o uso, poden aplicarse cargos do operador."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sen Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectada"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
@@ -373,7 +372,7 @@
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Ocultar"</string>
     <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> quere ser o cadro de diálogo de volume."</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Permitir"</string>
-    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Rexeitar"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Denegar"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> é o cadro de diálogo de volume"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca para restaurar o orixinal."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 73ec483..65ee915 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"अनलॉक करें"</string>
     <string name="phone_label" msgid="2320074140205331708">"फ़ोन खोलें"</string>
     <string name="camera_label" msgid="7261107956054836961">"कैमरा खोलें"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धति‍ बटन स्विच करें."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"संगतता ज़ूम बटन."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"छोटी से बड़ी स्‍क्रीन पर ज़ूम करें."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लूटूथ कनेक्ट किया गया."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हॉटस्‍पॉट को चालू किया गया."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्‍क्रीन कास्‍ट करना रुक गया."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"स्क्रीन की स्क्रीन की रोशनी"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेल्युलर डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बंद है"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"आपके डिवाइस ने डेटा बंद कर दिया है क्योंकि आपके द्वारा सेट की गई सीमा पार हो गई है.\n\nइसे फिर से चालू करने से आपका वाहक शुल्क ले सकता है."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा चालू करें"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटा रोक दिया गया है"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"चूंकि आपके निर्धारित डेटा की सीमा, सीमा पर पहुंच गई थी, इसलिए डिवाइस ने इस चक्र के रिमाइंडर के लिए डेटा उपयोग को रोक दिया है.\n\nफिर से शुरू करने से आपके वाहक की ओर से शुल्क लगाया जाता है."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"फिर से शुरू करें"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"कोई इंटरनेट कनेक्शन नहीं"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाई-फ़ाई  कनेक्‍ट किया गया"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS को खोजा जा रहा है"</string>
@@ -373,5 +372,5 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमति दें"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार करें"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> वॉल्यूम संवाद है"</string>
-    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल को पुनर्स्थापित करने के लिए स्पर्श करें."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल वॉल्यूम को फिर से लाने के लिए स्पर्श करें."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index be21b3c..113a0cf 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -89,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"otključavanje"</string>
     <string name="phone_label" msgid="2320074140205331708">"otvaranje telefona"</string>
     <string name="camera_label" msgid="7261107956054836961">"otvaranje fotoaparata"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za promjenu načina unosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb za kompatibilnost zumiranja."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zumiranje manjeg zaslona na veći."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth povezan."</string>
@@ -202,12 +201,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna žarišna točka uključena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Emitiranje zaslona zaustavljeno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svjetlina zaslona"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilni podaci isključeni"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Podaci su isključeni"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Uređaj je isključio podatke jer je dosegnuo ograničenje koje ste postavili.\n\nAko ih ponovno uključite, mogući su dodatni troškovi za mobilne usluge."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Uključi podatke"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G – 3G podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilni podaci pauzirani"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Podaci su pauzirani"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Budući da je dosegnuto postavljeno ograničenje podataka, uređaj je pauzirao upotrebu podataka za preostali dio ovog ciklusa.\n\nMobilni operater može naplatiti daljnju upotrebu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nastavi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nema internetske veze"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Traženje GPS-a"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 5d6a599..bdad948 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"feloldás"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefon megnyitása"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamera megnyitása"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Beviteli mód váltása gomb."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kompatibilitási zoom gomb."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kicsinyítsen a nagyobb képernyőhöz."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth csatlakoztatva."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"A mobil hotspot bekapcsolva."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A képernyő átküldése leállítva."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"A kijelző fényereje"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"A 2G-s és 3G-s adatkapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"A 4G-s adatkapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"A mobiladat-kapcsolat nem használható"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Az adatkapcsolat ki van kapcsolva"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Eszköze leállította az adatkapcsolatot, mert Ön elérte a beállított adatkorlátot.\n\nAz adatkapcsolat újbóli bekapcsolása után szolgáltatója többletköltséget számíthat fel."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Adatkapcsolat engedélyezése"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"A 2G és 3G adatforgalom szünetel."</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"A 4G adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"A mobilhálózati adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Az adatforgalom szünetel"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Mivel elérte a beállított adatkorlátot, az eszköz a ciklus fennmaradó részére felfüggesztette az adathasználatot.\n\nHa mégis használja az adatkapcsolatot, akkor szolgáltatója többletköltséget számíthat fel."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Folytatás"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nincs internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi csatlakoztatva"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS keresése"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index abef9a0..6cc1292 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ապակողպել"</string>
     <string name="phone_label" msgid="2320074140205331708">"բացել հեռախոսը"</string>
     <string name="camera_label" msgid="7261107956054836961">"բացել ֆոտոխցիկը"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Միացնել մուտքագրման եղանակի կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Համատեղելիության խոշորացման կոճակը:"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Դիտափոխել փոքրից ավելի մեծ էկրան:"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-ը միացված է:"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Շարժական կապի WiFi ցրիչը միացավ:"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Էկրանի հեռարձակումն ընդհատվեց:"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ցուցադրել պայծառությունը"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Բջջային տվյալներն անջատված են"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Տվյալների կապն անջատված է"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Տվյալների կապը ձեր սարքում անջատվեց, քանի որ դուք հատել եք նշված սահմանաչափը:\n\nԱյն հետ միացնելուց հետո հնարավոր են հավելյալ վճարներ ձեր օպերատորից:"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Միացնել տվյալների կապը"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2Գ-3Գ տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Գ տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Բջջային տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Տվյալների օգտագործումը դադարեցված է"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Քանի որ ձեր սահմանված տվյալների սահմանաչափը սպառվել է, սարքն այլևս չի օգտագործի տվյալները այս ցիկլի մնացած ընթացքում:\n\nԵթե վերսկսեք, հնարավոր է կիրառվեն գանձումներ ձեր օպերատորի կողմից:"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Վերսկսել"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ինտերնետ կապ չկա"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ը միացված է"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Որոնում է GPS"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 451983d..26cad0c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
     <string name="phone_label" msgid="2320074140205331708">"buka ponsel"</string>
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tombol beralih metode masukan."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tombol perbesar/perkecil kompatibilitas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Perbesar dari layar kecil ke besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tersambung."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot seluler diaktifkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmisi layar berhenti."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan tampilan"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G nonaktif"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G nonaktif"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data seluler nonaktif"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data nonaktif"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Perangkat Anda menonaktifkan data karena data mencapai batas yang Anda setel.\n\nMengaktifkan kembali data dapat membuat Anda terkena biaya dari operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktifkan data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data seluler dijeda"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Karena batas data yang disetel telah tercapai, perangkat telah menjeda penggunaan data selama sisa waktu siklus ini.\n\nMelanjutkan dapat mengakibatkan tagihan dari operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Lanjutkan"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tidak ada sambungan internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tersambung"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Menelusuri GPS"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index c616ab3..c7afebc 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"taka úr lás"</string>
     <string name="phone_label" msgid="2320074140205331708">"opna síma"</string>
     <string name="camera_label" msgid="7261107956054836961">"opna myndavél"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Hnappur til að skipta um innsláttaraðferð."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Hnappur fyrir samhæfisaðdrátt."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aðlaga forrit fyrir lítinn skjá að stærri skjá."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth tengt."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Kveikt á farsímaaðgangsstað."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjáútsendingu hætt."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Birtustig skjás"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Slökkt er á 2G- og 3G-gögnum"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Slökkt er á 4G-gögnum"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Slökkt er á farsímagögnum"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Slökkt er á gagnaflutningi"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Slökkt var á gagnaflutningi í tækinu vegna þess að hámarkinu sem þú valdir var náð.\n\nSímafyrirtækið þitt kann að taka gjald ef þú kveikir á honum aftur."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Kveikja á gagnaflutningi"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Slökkt er á 2G- og 3G-gögnum"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Slökkt er á 4G-gögnum"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Slökkt er á farsímagögnum"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Slökkt er á gagnanotkun"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Þar sem gagnahámarkinu var náð hefur tækið slökkt á gagnanotkun það sem eftir er af þessu tímabili.\n\nEf þú heldur áfram kann það að leiða til kostnaðar frá símafyrirtækinu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Halda áfram"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Engin nettenging"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tengt"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Leitar að GPS"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index a9a7297..7f5224e 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"sblocca"</string>
     <string name="phone_label" msgid="2320074140205331708">"apri telefono"</string>
     <string name="camera_label" msgid="7261107956054836961">"apri fotocamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Pulsante per cambiare metodo di immissione."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Pulsante zoom compatibilità."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom inferiore per schermo più grande."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth collegato."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspot mobile attivato."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Trasmissione dello schermo interrotta."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminosità dello schermo"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dati 2G-3G disattivati"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dati 4G disattivati"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Rete dati disattivata"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dati disattivati"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Il tuo dispositivo ha disattivato il traffico dati perché hai raggiunto il limite prestabilito.\n\nLa riattivazione potrebbe comportare l\'applicazione di costi aggiuntivi da parte del tuo operatore."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Attiva i dati"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dati 2G-3G sospesi"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dati 4G sospesi"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dati cellulari sospesi"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dati sospesi"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Hai raggiunto il tuo limite di dati, pertanto sul dispositivo è stato sospeso l\'utilizzo di dati per la parte rimanente del ciclo.\n\nSe riprendi a utilizzare i dati, l\'operatore potrebbe addebitarti costi."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Riprendi"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nessuna connessione"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi connesso"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ricerca del GPS"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 70de38d..5090ca7 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"בטל את הנעילה"</string>
     <string name="phone_label" msgid="2320074140205331708">"פתח את הטלפון"</string>
     <string name="camera_label" msgid="7261107956054836961">"פתח את המצלמה"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"לחצן החלפת שיטת קלט."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"לחצן מרחק מתצוגה של תאימות."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"שנה מרחק מתצוגה של מסך קטן לגדול יותר."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"‏Bluetooth מחובר."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"נקודה לשיתוף אינטרנט בנייד מופעלת."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"העברת המסך הופסקה."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"בהירות תצוגה"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏נתונים בחיבור 2G-3G כובו"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏נתונים בחיבור 4G כובו"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"נתונים בחיבור סלולרי כובו"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"חיבור הנתונים כובה"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"המכשיר שלך כיבה את חיבור הנתונים מפני שהוא הגיע למגבלה שהגדרת.\n\nהפעלה מחדש עשויה להוביל לחיובים על ידי הספק."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"הפעל חיבור נתונים"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏השימוש בנתוני 2G-3G מושהה"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏השימוש בנתוני 4G מושהה"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"השימוש בנתונים סלולריים מושהה"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"השימוש בנתונים מושהה"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"מכיוון שהגעת למגבלת הנתונים שהגדרת, המכשיר השהה את השימוש בנתונים עד סוף התקופה.\n\nאם תמשיך, אתה עשוי לקבל חיובים מהספק."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"המשך"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"אין חיבור לאינטרנט"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi מחובר"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏מחפש GPS"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 1b44396..d106f91 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ロック解除"</string>
     <string name="phone_label" msgid="2320074140205331708">"電話を起動"</string>
     <string name="camera_label" msgid="7261107956054836961">"カメラを起動"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"入力方法の切り替えボタン。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"互換ズームボタン。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"小さい画面から大きい画面に拡大。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetoothに接続済み。"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"モバイルアクセスポイントをONにしました。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"画面のキャストが停止しました。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ディスプレイの明るさ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G~3Gデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Gデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"モバイルデータが無効になりました"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"データが無効になりました"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"設定された上限に達したため、端末のデータ接続が無効になりました。\n\n有効に戻すと、携帯通信会社から課金される可能性があります。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"データ接続を有効にする"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G~3Gデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4Gデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"モバイルデータは一時停止中です"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"データの一時停止"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"設定されたデータの上限に達したため、このサイクルの終了までこの端末でのデータの利用を一時停止しました。\n\n再開すると、携帯通信会社から課金される可能性があります。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"再開"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"インターネット未接続"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi接続済み"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSで検索中"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 1bf9099..cb8c609 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"განბლოკვა"</string>
     <string name="phone_label" msgid="2320074140205331708">"ტელეფონის გახსნა"</string>
     <string name="camera_label" msgid="7261107956054836961">"კამერის გახსნა"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"შეყვანის მეთოდის გადართვის ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"თავსებადი მასშტაბირების ღილაკი."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"შეცვალეთ პატარა ეკრანი უფრო დიდით."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth დაკავშირებულია."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"მობილური ქსელის წერტილი ჩაირთო."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ეკრანის გადაცემა შეჩერებულია."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ეკრანის სიკაშკაშე"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G მონაც. გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G მონაც. გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ფიჭური ინტერნეტი გამორთულია"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"მონაცემთა გადაცემა გამორთულია"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"თქვენმა მოწყობილობამ მონაცემები გამორთო, რადგან თქვენ მიერ დაყენებულ ლიმიტს მიაღწია.\n\nმისი კვლავ გააქტიურებით შესაძლოა დაგეკისროთ გადასახადი თქვენი ოპერატორისგან."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"მონაცემთა ჩართვა"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ფიჭური მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"მონაცემები შეჩერებულია"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"რადგან თქვენი მონაცემების ლიმიტი ამოწურულია, მოწყობილობამ შეაჭერა მონაცემების გამოყენება დარჩენილი ციკლისათვის. \n\n შეჯამაბ შეიძლება გამოიწვიოს თქვენს პროვაიდერთან დამატებითი ხარჯები."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"გაგრძელება"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ინტერნეტ კავშირი არ არის"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi დაკავშირებულია"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-ის ძებნა"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 805fca6..a6077a1 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"бекітпесін ашу"</string>
     <string name="phone_label" msgid="2320074140205331708">"телефонды ашу"</string>
     <string name="camera_label" msgid="7261107956054836961">"камераны ашу"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Енгізу әдісі түймесін ауыстыру."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Үйлесімділік ұлғайту түймесі."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Үлкендеу экранда кішірейту."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth қосылған."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобильді хотспот қосылды."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Экранды трансляциялау тоқтатылды."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дисплей жарықтығы"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G деректері өшірулі"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G деректері өшірулі"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Ұялы деректер өшірулі"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Деректер өшірулі"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Құрылғыңыз сіз орнатқан шекке жеткендіктен деректерді өшірді.\n\nОны қайтадан қосу оператордың ақылар алуына әкелуі мүмкін."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Деректерді қосу"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G деректері кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G деректері кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Ұялы деректер кідіртілді"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Деректер кідіртілді"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Орнатылған деректер шегіне жеткендіктен, құрылғы осы циклдың қалған бөлігі бойы деректерді пайдалануды кідіртті.\n\nЖалғастыру оператор ақыларына әкелуі мүмкін."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Жалғастыру"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланысы жоқ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi қосулы"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS қызметін іздеуде"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 52dd68c..47768ec 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ដោះ​សោ"</string>
     <string name="phone_label" msgid="2320074140205331708">"បើក​ទូរស័ព្ទ"</string>
     <string name="camera_label" msgid="7261107956054836961">"បើក​ម៉ាស៊ីន​ថត"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ប្ដូរ​ប៊ូតុង​វិធីសាស្ត្រ​បញ្ចូល។"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ប៊ូតុង​ពង្រីក​ត្រូវ​គ្នា។"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ពង្រីក/បង្រួម​​អេក្រង់​ពី​​ទៅធំ"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"បាន​តភ្ជាប់​ប៊្លូធូស។"</string>
@@ -201,12 +200,18 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"បាន​បើក​ហតស្ប៉ត​ចល័ត។"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"បាន​បញ្ឈប់​ការ​ចាត់​ថ្នាក់​អេក្រង់។"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ពន្លឺ​ការ​បង្ហាញ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ទិន្នន័យ 2G-3G បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ទិន្នន័យ 4G បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ទិន្នន័យ​ចល័ត​បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ទិន្នន័យ​បាន​បិទ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ឧបករណ៍​របស់​អ្នក​បាន​បិទ​ទិន្នន័យ ព្រោះ​វា​បាន​ដល់​​កម្រិត​​ដែល​អ្នក​បាន​កំណត់។\n\nបើក​វា​ឡើង​វិញ​អាច​គិត​លុយ​ពី​ក្រុមហ៊ុន​បញ្ជូន​របស់​អ្នក។"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"បើក​ទិន្នន័យ"</string>
+    <!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_mobile_title (4651001290947318931) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_title (3932437232199671967) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog (8453242888903772524) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_enable (1412395410306390593) -->
+    <skip />
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"គ្មាន​ការ​តភ្ជាប់​អ៊ីនធឺណិត"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"បាន​ភ្ជាប់​វ៉ាយហ្វាយ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ស្វែងរក GPS"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 6df8655..85fefec 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ಅನ್‌ಲಾಕ್ ಮಾಡು"</string>
     <string name="phone_label" msgid="2320074140205331708">"ಫೋನ್ ತೆರೆಯಿರಿ"</string>
     <string name="camera_label" msgid="7261107956054836961">"ಕ್ಯಾಮರಾ ತೆರೆಯಿರಿ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ಇನ್‌ಪುಟ್ ವಿಧಾನ ಬದಲಿಸು ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ಹೊಂದಾಣಿಕೆಯ ಝೂಮ್ ಬಟನ್."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ಚಿಕ್ಕ ಪರದೆಯಿಂದ ದೊಡ್ಡ ಪರದೆಗೆ ಝೂಮ್ ಮಾಡು."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ಬ್ಲೂಟೂತ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ಮೊಬೈಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್ ಆನ್ ಮಾಡಲಾಗಿದೆ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ಸ್ಕ್ರೀನ್ ಪ್ರಸಾರವನ್ನು ನಿಲ್ಲಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ಹೊಳಪನ್ನು ಪ್ರದರ್ಶಿಸಿ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ಡೇಟಾ ಆಫ್ ಆಗಿದೆ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ನೀವು ಹೊಂದಿಸಿದ ಮಿತಿಯನ್ನು ತಲುಪಿರುವ ಕಾರಣ ನಿಮ್ಮ ಸಾಧನವು ಡೇಟಾವನ್ನು ಆಫ್ ಮಾಡಿದೆ.\n\nಆನ್ ಮಾಡುವುದರಿಂದ ನಿಮ್ಮ ವಾಹಕದಲ್ಲಿ ಶುಲ್ಕಕ್ಕೆ ಕಾರಣವಾಗಬಹುದು."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ಡೇಟಾ ಆನ್ ಮಾಡಿ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ಡೇಟಾವನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ಸೆಲ್ಯುಲಾರ್ ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ಡೇಟಾ ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ಏಕೆಂದರೆ ನಿಮ್ಮ ಹೊಂದಾಣಿಕೆ ಡೇಟಾ ಮೀತಿಯನ್ನು ತಲುಪಿದೆ, ಈ ಆವರ್ತನೆಯ ಉಳಿದ ಭಾಗಕ್ಕೆ ಸಾಧನವು ಡೇಟಾ ಬಳಕೆಯನ್ನು ವಿರಾಮಗೊಳಿಸಿದೆ.\n\nಮುಂದುವರೆಯುವಿಕೆಯು ನಿಮ್ಮ ವಾಹಕದ ಶುಲ್ಕಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ಮುಂದುವರಿಸು"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ಗಾಗಿ ಹುಡುಕಲಾಗುತ್ತಿದೆ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 1266898..d6f8219 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"잠금 해제"</string>
     <string name="phone_label" msgid="2320074140205331708">"휴대전화 열기"</string>
     <string name="camera_label" msgid="7261107956054836961">"카메라 열기"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"입력 방법 버튼을 전환합니다."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"호환성 확대/축소 버튼입니다."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"작은 화면을 큰 화면으로 확대합니다."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"블루투스가 연결되었습니다."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"모바일 핫스팟을 사용합니다."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"화면 전송이 중지되었습니다."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"디스플레이 밝기"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"이동통신 데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"데이터 사용 중지됨"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"데이터가 설정 한도에 도달하여 사용 중지되었습니다.\n\n데이터를 다시 사용 설정하면 이동통신사로부터 대금이 청구될 수 있습니다."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"데이터 사용 설정"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"모바일 데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"데이터 사용 중지됨"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"설정된 데이터 한도에 도달했기 때문에 기기에서 사이클의 나머지 기간 동안 데이터 사용을 일시 중지했습니다. \n\n데이터 사용을 재개하면 이동통신사 요금이 청구될 수 있습니다."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"재개"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"인터넷에 연결되지 않음"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 연결됨"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS 검색 중"</string>
@@ -369,14 +368,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"다음번에 설정에서 사용 설정하면 다시 표시됩니다."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"숨기기"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g>이(가) 볼륨 대화가 되려고 합니다."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"허용"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"거부"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>은(는) 볼륨 대화입니다."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"원본을 복원하려면 터치하세요."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index d2a35cd..0029d67 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -113,7 +113,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"кулпуну ачуу"</string>
     <string name="phone_label" msgid="2320074140205331708">"телефонду ачуу"</string>
     <string name="camera_label" msgid="7261107956054836961">"камераны ачуу"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Киргизүү ыкмасын которуу баскычы."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Масштабды сыйыштыруу баскычы."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Кичинекейди чоң экранга масштабдоо."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth байланышта"</string>
@@ -226,12 +225,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилдик байланыш түйүнү күйгүзүлдү."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Тышкы экранга чыгаруу аракети токтотулду."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Жарыктыгын көрсөтүү"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2Гб-3Гб көлөмдөгү дайындар өчүрүлдү."</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4Гб көлөмдөгү дайындар өчүрүлдү"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Уюктук дайындар тармагы өчүк"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дайындарды кабыл алуу өчүрүлгөн."</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Белгиленген эң жогорку чекке жеткендиктен, түзмөгүңүз дайындарды кабыл алууну токтотту.\n\nДайындарды кабыл алууну улантам десеңиз, операторго акы төлөп калышыңыз мүмкүн."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Дайындарды алууну иштетүү"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дайындары тындырылды."</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дайындары тындырылды"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Уюлдук дайындар тындырылды"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дайындар тындырылды"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Киргизиле турган дайындар белгиленген эң жогорку чекке жеткендиктен, ушул мерчимдин калган бөлүгүндө түзмөгүңүздө дайындардын колдонулушу тындырылды.\n\nУлантсаңыз, байланыш операторуңузга акы төлөп калышыңыз мүмкүн."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Улантуу"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет байланыш жок"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi байланышта"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS издөө"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index ac39b3c..cc3d0cc 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ປົດລັອກ"</string>
     <string name="phone_label" msgid="2320074140205331708">"​ເປີດ​​ແປ້ນ​ໂທ​ລະ​ສັບ"</string>
     <string name="camera_label" msgid="7261107956054836961">"ເປີດ​ກ້ອງ"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ປຸ່ມສະລັບຮູບແບບການປ້ອນຂໍ້ມູນ."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ປຸ່ມຊູມທີ່ໃຊ້ຮ່ວມກັນໄດ້."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ຊູມຈໍນ້ອຍໄປເປັນຈໍຂະຫນາດໃຫຍ່."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ເຊື່ອມຕໍ່ Bluetooth ແລ້ວ."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ເປີດ​ຮັອດ​ສະ​ປອດ​ເຄື່ອນ​ທີ່​ແລ້ວ."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"ຢຸດ​ການ​ສົ່ງ​​ພາບ​ໜ້າ​ຈໍ​ແລ້ວ."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"​ຄວາມ​ແຈ້ງ​​ຂອງ​ຈໍ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ຂໍ້​ມູນ 2G-3G ​ແມ່ນ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ຂໍ້​ມູນ 4G ແມ່ນ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ຂໍ້​ມູ​ນມ​ື​ຖື​ຖືກ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ຂໍ້​ມູນ​ຖື​ກ​ປິດ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ​ປິດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ເນື່ອງ​ຈາກ​ມັນ​ໃຊ້​ຮອດ​ຈຳ​ນວນ​ທີ່​ທ່ານ​ກຳ​ນົດ​ໄວ້​ແລ້ວ.\n\nການ​ເປີດ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ຄືນ​ອາດ​ເຮັດ​ໃຫ​້​ຜູ່​ໃຫ້​ບໍ​ລິ​ການ​ຮຽກ​ເກັບ​ເງິນ​ທ່ານ​ເພີ່ມ​ໄດ້."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"​ເປີດ​ນຳ​ໃຊ້​ຂໍ້​ມູນ"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"ຂໍ້​ມູນ 2G​-3G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"ຂໍ້​ມູນ 4G ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"ຂໍ້​ມູນເຊວ​ລູ​ລາຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ຂໍ້​ມູນ​ຢຸດ​ຊົ່ວ​ຄາວແລ້ວ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ເນື່ອງ​ຈາກວ່າ​ຮອດ​ຂີດ​ຈຳ​ກັດ​ຂໍ້​ມູນ​ທີ່​ຕັ້ງ​ໄວ້​ຂອ​ງ​ທ່ານ​ແລ້ວ, ອຸ​ປະ​ກອນ​ຢຸດ​ການ​ນຳ​ໃຊ້​ຂໍ້​ມູນ​ສຳ​ລັບ​ສ່ວນ​ທີ່​ຍັງ​ເຫຼືອ​ຂອງ​ຮອບ​ວຽນ​ນີ້.\n\nການ​ເລີ່ມ​ຕໍ່​ອາດ​ຈະ​ນຳ​ໄປ​ສູ່​ການ​ປ່ຽນ​ແປງ​ຈາກ​ຜູ້​ໃຫ້​ບໍ​ລິ​ການ​ເຄືອ​ຂ່າຍ​ຂອງ​ທ່ານ."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ເລີ່ມຕໍ່"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ເຊື່ອມ​ຕໍ່ Wi-​-Fi ແລ້ວ"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"ກຳລັງຊອກຫາ GPS"</string>
@@ -369,14 +368,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼື​ບໍ່?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"​ມັນ​ຈະ​ສະ​ແດງ​ຄືນ​ໃໝ່​ເມື່ອ​ທ່ານ​ເປີດ​ນຳ​ໃຊ້​ມັນ​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ຄັ້ງ​ຕໍ່​ໄປ."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"ເຊື່ອງ"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ຕ້ອງ​ການໃຫ້​ເປັນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ອະນຸຍາດ"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ປະຕິເສດ"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ແມ່ນ​ໜ້າ​ຕ່າງ​ລະ​ດັບ​ສຽງ"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ສໍາ​ຜັດ​ເພື່ອກູ້​ຄືນ​ຕົ້ນ​ສະ​ບັບ​."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 1b523a2..b83f88f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"atrakinti"</string>
     <string name="phone_label" msgid="2320074140205331708">"atidaryti telefoną"</string>
     <string name="camera_label" msgid="7261107956054836961">"atidaryti fotoaparatą"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Perjungti įvesties metodo mygtuką."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Suderinamumo priartinimo mygtukas."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Padidinti ekraną."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"„Bluetooth“ prijungtas."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiliojo ryšio viešosios interneto prieigos taškas įjungtas."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrano perdavimas sustabdytas."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrano šviesumas"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiliojo ryšio duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Duomenys išjungti"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Įrenginys išjungė duomenis, nes buvo pasiektas nustatytas limitas.\n\nVėl juos įjungus gali būti taikomi operatoriaus mokesčiai."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Įjungti duomenis"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Korinio ryšio duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Duomenys pristabdyti"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kadangi buvo pasiektas nustatytas duomenų limitas, įrenginys pristabdė duomenų naudojimą likusį šio ciklo laikotarpį.\n\nAtnaujinus gali būti taikomi operatoriaus mokesčiai."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atnaujinti"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nėra interneto ryš."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Prisij. prie „Wi-Fi“"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Ieškoma GPS"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4461006..cc2702b 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -89,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"atbloķēt"</string>
     <string name="phone_label" msgid="2320074140205331708">"atvērt tālruni"</string>
     <string name="camera_label" msgid="7261107956054836961">"atvērt kameru"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ievades metodes maiņas poga."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Saderības tālummaiņas poga."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Veikt tālummaiņu no mazāka ekrāna uz lielāku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth savienojums ir izveidots."</string>
@@ -202,12 +201,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilais tīklājs ir ieslēgts."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekrāna apraidīšana ir apturēta."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekrāna spilgtums"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilie dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dati ir atslēgti"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Jūsu ierīcē tika atslēgta datu lietošana, jo tika sasniegts jūsu noteiktais ierobežojums.\n\nJa atkal ieslēgsiet datu lietošanu, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ieslēgt datus"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilo datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Datu lietojums ir apturēts"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Tika sasniegts iestatītais datu lietojuma ierobežojums, tādēļ ierīcē ir apturēts datu lietojums cikla atlikušajā periodā.\n\nJa atsāksiet lietot datus, iespējams, jūsu mobilo sakaru operators iekasēs maksu."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Atsākt"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Nav interneta sav."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Izv. sav. ar Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Notiek GPS meklēšana..."</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index d65bf65..a5bb833 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"отклучи"</string>
     <string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"отвори камера"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Копче за префрање метод на внес."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Копче за компатибилност на зум."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумот е помал на поголем екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth е поврзан."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилната точка на пристап е вклучена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Емитувањето на екранот запре."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветленост на екранот"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Податоците 2G-3G се исклучени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Податоците 4G се исклучени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилните податоци се исклучени"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Податоците се исклучени"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Вашиот уред ги исклучи податоците затоа што го достигнаа лимитот што го поставивте.\n\nСо повторно вклучување, операторот може да ви наплати за тоа."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Вклучи податоци"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Податоците 2G-3G се паузирани"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Податоците 4G се паузирани"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилните податоци се паузирани"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Податоците се паузирани"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Поради тоа што го достигнавте поставеното ограничување на податоци, уредот го паузираше користењето податоци до крајот на циклусот.\n\nОператорот може да ви наплати ако продолжите."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Продолжи"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Поврзано на Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Се пребарува за ГПС"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 467453e..46acaa0 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"അൺലോക്കുചെയ്യുക"</string>
     <string name="phone_label" msgid="2320074140205331708">"ഫോൺ തുറക്കുക"</string>
     <string name="camera_label" msgid="7261107956054836961">"ക്യാമറ തുറക്കുക"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ടൈപ്പുചെയ്യൽ രീതി ബട്ടൺ മാറുക."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"അനുയോജ്യതാ സൂം ബട്ടൺ."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ചെറുതിൽ നിന്ന് വലിയ സ്‌ക്രീനിലേക്ക് സൂം ചെയ്യുക."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ബ്ലൂടൂത്ത് കണക്‌റ്റുചെയ്തു."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"മൊബൈൽ ഹോട്ട്‌സ്‌പോട്ട് ഓണാക്കി."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"സ്ക്രീൻ കാസ്‌റ്റുചെയ്യൽ നിർത്തി."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ഡിസ്പ്ലേ തെളിച്ചം"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"സെല്ലുലാർ ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ഡാറ്റ ഓഫാണ്"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"നിങ്ങൾ സജ്ജീകരിച്ചിരിക്കുന്ന പരിധിയിൽ എത്തിച്ചേർന്നിരിക്കുന്നതിനാൽ ഉപകരണം ഡാറ്റ ഓഫുചെയ്‌തു.\n\nഅത് തിരികെ ഓണാക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കീടാക്കുന്നതിന് ഇടയാക്കാം."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ഡാറ്റ ഓണാക്കുക"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"സെല്ലുലാർ ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ഡാറ്റ താൽക്കാലികമായി നിർത്തി"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"നിങ്ങളുടെ സജ്ജീകരിച്ച ഡാറ്റ പരിധിയിലെത്തിയതിനാൽ, ഈ സൈക്കിളിന്റെ അവശേഷിക്കുന്ന ഡാറ്റ ഉപയോഗത്തെ ഉപകരണം താൽക്കാലികമായി നിർത്തി.\n\nപുനരാരംഭിക്കുന്നത്, നിങ്ങളുടെ കാരിയറിൽ നിന്ന് നിരക്കുകൾ ഈടാക്കിയേക്കാം."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"പുനരാരംഭിക്കുക"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ഇന്റർനെറ്റ് കണക്ഷൻ ഇല്ല"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS-നായി തിരയുന്നു"</string>
@@ -373,5 +372,5 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"അനുവദിക്കുക"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"നിരസിക്കുക"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g>, വോളിയം ഡയലോഗാണ്"</string>
-    <string name="volumeui_notification_text" msgid="1826889705095768656">"യഥാർത്ഥമായത് പുനഃസ്ഥാപിക്കാൻ സ്‌പർശിക്കുക."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"ആദ്യത്തേത് പുനഃസ്ഥാപിക്കാൻ സ്‌പർശിക്കുക."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index a02ccf2..fd16012 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -86,7 +86,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"тайлах"</string>
     <string name="phone_label" msgid="2320074140205331708">"утас нээх"</string>
     <string name="camera_label" msgid="7261107956054836961">"камер нээх"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Оруулах аргыг сэлгэх товч."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Тохиромжтой өсгөх товч."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Жижгээс том дэлгэцрүү өсгөх."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Блютүүт холбогдсон."</string>
@@ -199,12 +198,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобайл хотспотыг асаасан."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Дэлгэц дамжуулалт зогссон."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Дэлгэцийн гэрэлтэлт"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Үүрэн дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дата идэвхгүй"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Таны тогтоосон хязгаарт хүрсэн учир төхөөрөмж датаг унтраасан.\n\nҮүнийг асааснаар таны төлбөр нэмэгдэхэд хүргэж болзошгүй."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Датаг асаах"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Гар утасны дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Дата-г түр зогсоосон байна"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Таны багц дата эрхийн дээд хэмжээнд хүрсэн байгаа тул төхөөрөмж нь үлдсэн хэсэгт дата хэрэглээг түр зогсоосон байна.\n\nТа үйлдлийг үргэлжлүүлэхийг хүсвэл үйлчилгээ үзүүлж буй үүрэн холбооны газраас нэмж дата эрх авна уу."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Үргэлжлүүлэх"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Интернет холболт байхгүй"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi холбогдсон"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS хайж байна"</string>
@@ -367,14 +366,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>-ийг нуух уу?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Тохируулгын хэсэгт үүнийг асаахад энэ дахин харагдана."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Нуух"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог болохыг хүсч байна."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Зөвшөөрөх"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Татгалзах"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> нь дууны диалог юм."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Анхны хувилбарыг эргүүлэн хадгалахыг хүсвэл хүрнэ үү."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 9399957..afaa65d 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"अनलॉक करा"</string>
     <string name="phone_label" msgid="2320074140205331708">"फोन उघडा"</string>
     <string name="camera_label" msgid="7261107956054836961">"कॅमेरा उघडा"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट पद्धत स्‍विच करा बटण."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"सुसंगतता झूम बटण."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"लहानपासून मोठ्‍या स्‍क्रीनवर झूम करा."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब कनेक्‍ट केले."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाईल हॉटस्पॉट चालू केला."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रीन कास्ट करणे थांबले."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेल्युलर डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बंद आहे"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"डेटाने आपण सेट  केलेली मर्यादा गाठल्‍यामुळे आपल्‍या डिव्‍हाइसने तो बंद केला.\n\n तो पुन्‍हा चालू केल्‍यास आपल्‍या वाहकाकडील शुल्‍क लागू शकेल."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा चालू करा"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्युलर डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डेटास विराम दिला आहे"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"आपली सेट केलेली डेटा मर्यादा गाठल्यामुळे, डिव्हाइसने या चक्राच्या उर्वरित डेटा वापरास विराम दिला आहे.\n\nपुन्हा सुरु करण्यामुळे आपल्या वाहकाकडून शुल्क आकारले जाऊ शकते."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुन्हा सुरु करा"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इंटरनेट कनेक्शन नाही"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाय-फाय कनेक्ट केले"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS शोधत आहे"</string>
@@ -369,9 +368,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"आपण सेटिंग्जमध्ये ते पुढील वेळी चालू कराल तेव्हा ते पुन्हा दिसेल."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"लपवा"</string>
-    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा आकारमान संवाद होऊ इच्छितो."</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद होऊ इच्छितो."</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमती द्या"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"नकार द्या"</string>
-    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा आकारमान संवाद आहे"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> हा व्हॉल्यूम संवाद आहे"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"मूळ पुनर्संचयित करण्यासाठी स्पर्श करा."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 72783a5..d0f3213 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"buka kunci"</string>
     <string name="phone_label" msgid="2320074140205331708">"buka telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"buka kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Butang tukar kaedah input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Butang zum keserasian."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Skrin zum lebih kecil kepada lebih besar."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth disambungkan."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Tempat liputan mudah alih bergerak dihidupkan."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Penghantaran skrin dihentikan."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Kecerahan paparan"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data 2G-3G dimatikan"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data 4G dimatikan"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data selular dimatikan"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data dimatikan"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Peranti anda mematikan data kerana telah mencapai had yang anda tetapkan.\n\nMenghidupkan data semula boleh menyebabkan anda dikenakan caj oleh pembawa anda."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Hidupkan data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data 2G-3G dijeda"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data 4G dijeda"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data selular dijeda"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data dijeda"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Oleh kerana had data tetap anda telah dicapai, peranti telah menjeda penggunaan data bagi baki kitaran ini.\n\nMenyambung semula boleh menyebabkan anda dikenakan bayaran daripada pembawa anda."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Sambung semula"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Tiada smbg Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi disambungkan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Mencari GPS"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 6043929..b572ba2 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"သော့ဖွင့်ရန်"</string>
     <string name="phone_label" msgid="2320074140205331708">"ဖုန်းကို ဖွင့်ရန်"</string>
     <string name="camera_label" msgid="7261107956054836961">"ကင်မရာ ဖွင့်ရန်"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ထည့်သွင်းခြင်းခလုတ်အား ပြောင်းခြင်း"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"အံ့ဝင်သောချုံ့ချဲ့ခလုတ်"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ဖန်သားပြင်ပေါ်တွင် အသေးမှအကြီးသို့ချဲ့ခြင်း"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ဘလူးတုသ်ချိတ်ဆက်ထားမှု"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"မိုဘိုင်း ဟော့စပေါ့ ဖွင့်ထား။"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"မျက်နှာပြင် ကာစ်တင် လုပ်မှု ရပ်လိုက်ပြီ။"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"တောက်ပမှုကို ပြရန်"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ဆယ်လူလာ ဒေတာကို ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ဒေတာ ပိတ်ထား"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"သင်၏ ကိရိယာသည် သင်က သတ်မှတ်ခဲ့သည့် ကန့်သတ်ချက်ကို ပြည့်မီသွား၍ ပိတ်သွားသည်။ \n\n၎င်းကို ပြန်ပြီး ဖွင့်မှုအတွက် သင်၏ စီမံပေးသူ ထံမှ ငွေတောင်းခံ လာနိုင်ပါသည်။"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ဒေတာ ဖွင့်ပေးရန်"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G data ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"cellular data ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ဒေတာ ခေတ္တရပ်တန့်သည်"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"သင့် ဒေတာ အသုံးပြုမှု သတ်မှတ်ထားချက်သို့ ရောက်ရှိသောကြောင့်၊ ဤကာလအတွက် ကျန်ရှိသည့် ဒေတာအသုံးပြုမှုအား စက်ပစ္စည်းမှ ရပ်တန့်ထားသည်။\n\nဆက်လက်သွားပါက သင့်ဖုန်းဝန်ဆောင်မှုမှ သင့်အား ကုန်ကျစရိတ်တောင်းခံလိမ့်မည်။"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"ပြန်ဆက်လုပ်ရန်"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"အင်တာနက်မရှိ"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"ကြိုးမဲ့ဆက်သွယ်မှု"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSအားရှာဖွေသည်"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 9ea954e..b78723c 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås opp"</string>
     <string name="phone_label" msgid="2320074140205331708">"åpne telefonen"</string>
     <string name="camera_label" msgid="7261107956054836961">"åpne kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Bytt knapp for inndatametode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Zoomknapp for kompatibilitet."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom fra mindre til større skjerm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth er tilkoblet."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil Wi-Fi-sone er slått på."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Skjermcastingen er stoppet."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Lysstyrken på skjermen"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G- og 3G-data er slått av"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-datatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildatatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datatrafikk er slått av"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Datatrafikk er slått av på enheten din fordi du har nådd den angitte grensen.\n\nHvis du slår datatrafikken på igjen, kan det føre til belastninger fra operatøren din."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Slå på datatrafikk"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- og 3G-data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata er satt på pause"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data er satt på pause"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Fordi den angitte datagrensen ble nådd, har enheten satt databruk på pause for resten av denne syklusen. \n\nHvis du gjenopptar bruken, kan det føre til avgifter fra operatøren din."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Gjenoppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen Internett-forbindelse"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi tilkoblet"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Søker etter GPS"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 38b4d56..59c268e 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"खोल्नुहोस्"</string>
     <string name="phone_label" msgid="2320074140205331708">"फोन खोल्नुहोस्"</string>
     <string name="camera_label" msgid="7261107956054836961">"क्यामेरा खोल्नुहोस्"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"इनपुट विधि बटन स्विच गर्नुहोस्।"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"मिलाउने जुम बटन।"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"स्क्रिनलाई सानोबाट ठूलो पार्नुहोस्।"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"ब्लुटुथ जडान भयो।"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"मोबाइल हटस्पट खुला गरियो।"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"स्क्रिन कास्टिङ रोकियो।"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"प्रदर्शन चमक"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"सेलुलर डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"डेटा बन्द छ"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"तपाईंले सेट गर्नु भएको सीमा पुगेको हुनाले तपाईंको उपकरणले डेटा बंद गर्यो।\n\n यसलाई फिर्ता गर्दा आफ्नो वाहक बाट शुल्क लिन सक्छ।"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"डेटा खोल्नुहोस्"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G डाटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G डाटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"सेल्यूलर डाटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"डाटा रोकिएको छ"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"तपाईंले सेट गर्नुभएको डाटा सीमा पुगेकाले, उपकरणले यस चक्रको बाँकीको लागि डाटा प्रयोग रोकेको छ।\n\nपुन: सुरू गर्दा तपाईंको क्यारियरले शुल्कहरू लिन सक्छ।"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"पुनः सुरु गर्नुहोस्"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"इन्टरनेट जडान छैन"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"वाइफाइ जडित"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPSको लागि खोजी गर्दै"</string>
@@ -373,5 +372,5 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"अनुमति दिनुहोस्"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"अस्वीकार गर्नुहोस्"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> भोल्यूम संवाद हो"</string>
-    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल पुन: भण्डार गर्न छुनुहोस्।"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"मूल पुनर्स्थापना गर्न छुनुहोस्।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index be46153..4006618 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ontgrendelen"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefoon openen"</string>
     <string name="camera_label" msgid="7261107956054836961">"camera openen"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knop voor wijzigen invoermethode."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knop voor compatibiliteitszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kleiner scherm uitzoomen naar groter scherm."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-verbinding ingesteld."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobiele hotspot ingeschakeld."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Casten van scherm gestopt."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Helderheid van het scherm"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G-data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobiele data zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Gegevens zijn uitgeschakeld"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Uw apparaat heeft gegevens uitgeschakeld omdat de ingestelde limiet is bereikt.\n\nAls u gegevens weer inschakelt, kan uw provider kosten in rekening brengen."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Gegevens inschakelen"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G/3G-data zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobiele gegevens zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Gegevens zijn onderbroken"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Omdat de ingestelde gegevenslimiet is bereikt, heeft het apparaat het gegevensverbruik onderbroken voor de rest van deze cyclus.\n\nAls u het gegevensverbruik hervat, kan uw provider kosten in rekening brengen."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Hervatten"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Geen internetverbinding"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Verbonden via wifi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Zoeken naar GPS"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 5e6c632..1b9e1d4 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odblokuj"</string>
     <string name="phone_label" msgid="2320074140205331708">"otwórz telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"otwórz aparat"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Przycisk przełączania metody wprowadzania."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Przycisk powiększenia na potrzeby zgodności."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Powiększa mniejszy ekran do większego."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth połączony."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilny hotspot został włączony."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Zatrzymano przesyłanie ekranu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jasność wyświetlacza"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Połączenie danych 2G-3G wyłączone"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Połączenie danych 4G wyłączone"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Komórkowe połączenie danych jest wyłączone"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Połączenie danych jest wyłączone"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Połączenie danych na Twoim urządzeniu zostało wyłączone, ponieważ osiągnęło ustalony limit.\n\nJeśli włączysz je ponownie, operator może naliczyć opłaty."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Włącz połączenie danych"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Transmisja danych 2G-3G została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Transmisja danych 4G została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Komórkowa transmisja danych została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Transmisja danych została wstrzymana"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ponieważ został osiągnięty ustawiony przez Ciebie limit danych, urządzenie wstrzymało użycie danych na pozostałą część tego cyklu.\n\nWznowienie może spowodować naliczenie opłat przez operatora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Wznów"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Brak internetu"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: połączono"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Wyszukiwanie sygnału GPS"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index b9977ff..4cdb511 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir telemóvel"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir câmara"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alternar botão de método de introdução."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão zoom de compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zoom menor para ecrã maior."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ligado."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Zona Wi-Fi móvel ligada."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmissão do ecrã interrompida."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho do visor"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dados 2G-3G desligados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dados 4G desligados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dados de rede móvel desligados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dados desligados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desligou os dados porque atingiu o limite definido.\n\nVoltar a ligá-los pode resultar em cobranças por parte do operador."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ligar dados"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dados 2G-3G em pausa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dados 4G em pausa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Dados de redes móveis em pausa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dados em pausa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Uma vez que foi atingido o limite de dados definido, foi interrompida a utilização de dados no seu dispositivo durante o tempo restante deste ciclo.\n\nSe retomar a utilização, o seu operador pode efetuar cobranças."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem ligação internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ligado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"A procurar GPS"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 90913c9..461ac26 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"desbloquear"</string>
     <string name="phone_label" msgid="2320074140205331708">"abrir telefone"</string>
     <string name="camera_label" msgid="7261107956054836961">"abrir câmera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Alterar botão do método de entrada."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Botão de zoom da compatibilidade."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Aumentar a tela com zoom."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth conectado."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"O ponto de acesso móvel foi ativado."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"A transmissão de tela foi interrompida."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Brilho da tela"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Os dados 2G-3G foram desativados"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Os dados 4G foram desativados"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Os dados da rede celular foram desativados"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Os dados foram desativados"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"O dispositivo desativou os dados porque o limite definido foi atingido.\n\nAtivá-los novamente poderá resultar em cobranças de sua operadora."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Ativar dados"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Os dados 2G e 3G foram pausados"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Os dados 4G foram pausados"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Os dados da rede celular foram pausados"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Os dados foram pausados"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Como seu limite de dados definido foi atingido, o dispositivo pausou o uso de dados para o restante deste ciclo.\n\nA retomada pode gerar cobranças por parte da sua operadora."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Retomar"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Sem conexão à Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectado"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Buscando GPS"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2b815ab..fbaf763 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -89,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"deblocați"</string>
     <string name="phone_label" msgid="2320074140205331708">"deschideți telefonul"</string>
     <string name="camera_label" msgid="7261107956054836961">"deschideți camera foto"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Buton pentru comutarea metodei de introducere."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Buton zoom pentru compatibilitate."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Faceţi zoom de la o imagine mai mică la una mai mare."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Conectat prin Bluetooth."</string>
@@ -202,12 +201,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Hotspotul mobil este activat."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Transmiterea ecranului a fost oprită."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Luminozitatea ecranului"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Datele 2G-3G sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Datele 4G sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Datele mobile sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Datele sunt dezactivate"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Dispozitivul dvs. a dezactivat conexiunea de date deoarece s-a atins limita pe care ați setat-o.\n\nReactivarea conexiunii poate genera aplicarea de taxe de către operator."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Activați datele"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Conexiunea de date 2G – 3G este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Conexiunea de date 4G este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Conexiunea de date mobile este întreruptă"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Conexiunea de date este întreruptă"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Deoarece limita setată pentru date a fost atinsă, dispozitivul a întrerupt utilizarea datelor pentru restul acestui ciclu.\n\nReluarea utilizării de date poate genera aplicarea de taxe de către operator."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Reluați"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Fără conex. internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi conectat"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Se caută GPS"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 8904be2..b57ccb3 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"Разблокировать."</string>
     <string name="phone_label" msgid="2320074140205331708">"Открыть телефон."</string>
     <string name="camera_label" msgid="7261107956054836961">"Открыть камеру."</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка переключения способа ввода."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабирования (режим совместимости)"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Уменьшение изображения для увеличения свободного места на экране."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth-соединение установлено."</string>
@@ -205,12 +204,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Точка доступа включена."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляция прекращена."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яркость экрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Передача данных 2G/3G отключена"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Передача данных 4G отключена"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Передача мобильных данных отключена"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Передача данных отключена"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Передача данных отключена, поскольку достигнут установленный вами лимит.\n\nВы можете снова включить ее, однако за переданные данные оператор может взимать дополнительную плату."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Включить передачу данных"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передача данных 2G и 3G приостановлена"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передача данных 4G приостановлена"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передача мобильных данных приостановлена"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передача данных приостановлена"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Передача данных выключена до конца цикла, поскольку достигнут установленный вами лимит.\n\nЕсли вы возобновите ее, оператор может взимать плату за дополнительный расход трафика."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Возобновить"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нет интернет-подключения"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi подключено"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Поиск GPS"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index f8d2293..1e03b56 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"අඟුල අරින්න"</string>
     <string name="phone_label" msgid="2320074140205331708">"දුරකථනය විවෘත කරන්න"</string>
     <string name="camera_label" msgid="7261107956054836961">"කැමරාව විවෘත කරන්න"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ආදාන ක්‍රමය මාරු කිරීමේ බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ගැළපෙන විශාලන බොත්තම."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"විශාල තිරය වෙත කුඩාව විශාලනය කරන්න."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"බ්ලූටූත් සම්බන්ධිතයි."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"ජංගම හොට්ස්පොටය සක්‍රිය කරන ලදි."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"තිරය විකාශය කිරීම නැවත් වන ලදි."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"දීප්තිය දර්ශනය කරන්න"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"සෙලියුලර් දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"දත්ත අක්‍රියයි"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"ඔබ සකසන ලද දත්ත සීමාවට එය ළඟාවී ඇති නිසා ඔබගේ උපාංගයේ දත්ත අක්‍රිය කර ඇත.\n\nඑය නැවත සක්‍රිය කිරීමෙන් ඔබගේ වාහකය ඇතැම් විට අය කර ගැනීමට හේතු වේ."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"දත්ත සක්‍රිය කරන්න"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"සෙල්‍යුලර් දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"දත්ත විරාම කර ඇත"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"ඔබ සකසා ඇති දත්ත සීමාවට ළඟා වූ නිසා, උපාංගය මගින් මෙම චක්‍රයේ ඉතිරිය සඳහා දත්ත භාවිතය විරාම කර ඇත. \n\nනැවත පටන් ගැනීමෙන් ඔබගේ වාහකයෙන් අය කිරීම්වලට පොළඹවනු ඇත."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"නැවත පටන්ගන්න"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"අන්තර්ජාල සම්බන්ධතාවයක් නැත"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi සම්බන්ධිතයි"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS සඳහා සොයමින්"</string>
@@ -373,5 +372,5 @@
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"ඉඩ දෙන්න"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"ප්‍රතික්ෂේප කරන්න"</string>
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ධාරිතා සංවාදයයි"</string>
-    <string name="volumeui_notification_text" msgid="1826889705095768656">"මුල් තත්වය නැවත ප්‍රතිසාධනය කිරීමට ස්පර්ශ කරන්න."</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"මුල් තත්ත්වය නැවත ප්‍රතිසාධනය කිරීමට ස්පර්ශ කරන්න."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index ddb45b4a..eba3977 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odomknúť"</string>
     <string name="phone_label" msgid="2320074140205331708">"otvoriť telefón"</string>
     <string name="camera_label" msgid="7261107956054836961">"spustiť fotoaparát"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Tlačidlo prepnutia metódy vstupu."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Tlačidlo úpravy veľkosti z dôvodu kompatibility."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zväčšiť menší obrázok na väčšiu obrazovku."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth pripojené."</string>
@@ -205,12 +204,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilný hotspot je zapnutý."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Prenášanie bolo zastavené."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Jas displeja"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"dáta 2G–3G sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"dáta 4G sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobilné dáta sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dáta sú vypnuté"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Zariadenie vyplo dáta, pretože dosiahlo limit, ktorý ste nastavili.\n\nAk ich znova zapnete, môže to viesť k účtovaniu poplatkov operátora."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Zapnúť dáta"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Dátové prenosy 2G a 3G sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Dátové prenosy 4G sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobilné dáta sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dáta sú pozastavené"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Keďže ste dosiahli nastavený limit pre mobilné dáta, na zariadení bola pre zvyšok tohto cyklu pozastavená spotreba dát.\n\nJej opätovné spustenie môže mať za následok účtovanie poplatkov vaším operátorom."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Znova spustiť"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Bez prip. na Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi: pripojené"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Vyhľadávanie satelitov GPS"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 24b92c4..65d684b 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"odkleni"</string>
     <string name="phone_label" msgid="2320074140205331708">"odpri telefon"</string>
     <string name="camera_label" msgid="7261107956054836961">"odpri fotoaparat"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Gumb za preklop načina vnosa."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Gumb povečave za združljivost."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Povečava manjšega na večji zaslon."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Povezava Bluetooth vzpostavljena."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobilna dostopna točka je vklopljena."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Predvajanje zaslona je ustavljeno."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Svetlost zaslona"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Prenos podatkov v omrežjih 2G/3G je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Prenos podatkov v omrežjih 4G je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Prenos podatkov v mobilnih omrežjih je izklopljen"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Prenos podatkov je izklopljen"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Naprava je izklopila prenos podatkov, ker je bila dosežena omejitev, ki ste jo nastavili.\n\nČe prenos spet vklopite, vam bo operater morda zaračunal stroške."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Vklopi prenos podatkov"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Prenos podatkov v omrežju 2G/3G je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Prenos podatkov v omrežju 4G je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Prenos mobilnih podatkov je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Prenos podatkov je zaustavljen"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dosegli ste nastavljeno omejitev količine prenesenih podatkov, zato je naprava zaustavila porabo podatkov za preostanek cikla.\n\nČe nadaljujete s porabo, boste morda morali plačati stroške operaterju."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Nadaljuj"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ni internetne povez."</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi povezan"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Iskanje GPS-a"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 552b377..fca2a8a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -89,7 +89,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"откључај"</string>
     <string name="phone_label" msgid="2320074140205331708">"отвори телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"отвори камеру"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Дугме Промени метод уноса."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Дугме Зум компатибилности."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Зумирање са мањег на већи екран."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth је прикључен."</string>
@@ -202,12 +201,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобилни хотспот је укључен."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Пребацивање екрана је заустављено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Осветљеност екрана"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G–3G подаци су искључени"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G подаци су искључени"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобилни пренос података је искључен"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Пренос података је искључен"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Уређај је искључио пренос података јер је достигао ограничење које сте поставили.\n\nАко га поново укључите, можда ће вам мобилни оператер наплатити трошкове."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Укључи пренос података"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G–3G подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Мобилни подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Подаци су паузирани"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Због тога што сте достигли подешено ограничење за податке, уређај је паузирао коришћење података током остатка овог циклуса.\n\nАко наставите, мобилни оператер може да вам наплати додатне трошкове."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Настави"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Нема интернет везе"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi је повезан"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Тражи се GPS"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index c8587c0..020e777 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"lås upp"</string>
     <string name="phone_label" msgid="2320074140205331708">"öppna mobilen"</string>
     <string name="camera_label" msgid="7261107956054836961">"öppna kameran"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Knapp för byte av inmatningsmetod."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Knapp för kompatibilitetszoom."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Zooma mindre skärm till större."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ansluten."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Den mobila trådlösa surfzonen har aktiverats."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Castningen av skärmen har stoppats."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Skärmens ljusstyrka"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-/3G-data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G-data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobildata har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data har inaktiverats"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Data har stängts av på enheten eftersom den angivna gränsen har uppnåtts.\n\nOm du aktiverar den igen kan avgifter från operatören tillkomma."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Aktivera uppgifter"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G- och 3G-data har pausats"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G-data har pausats"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobildata har pausats"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Dataanvändningen har pausats"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Eftersom du har nått den angivna datagränsen har dataanvändningen pausats under resten av perioden.\n\nOm du återupptar dataanvändningen kan avgifter från operatören tillkomma."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Återuppta"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ingen anslutning"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi-ansluten"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Sökning efter GPS pågår"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d933224..ca4baee 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"fungua"</string>
     <string name="phone_label" msgid="2320074140205331708">"fungua simu"</string>
     <string name="camera_label" msgid="7261107956054836961">"fungua kamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Swichi kitufe cha mbinu ingizi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kichupo cha kukuza kwa utangamanifu"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kuza kidogo kwa skrini kubwa."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth imeunganishwa."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mtandao-hewa unaoweza kuhamishika umewashwa."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Utumaji wa skrini umesitishwa."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ung\'aavu wa skrini"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Data ya 2G-3G imezimwa"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Data ya 4G imezimwa"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Data ya simu ya mkononi imezimwa"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Data imezimwa"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Kifaa chako kilizima data kwa sababu kilifikia kikomo ulichoweka.\n\nKuwasha data tena kunaweza kusababisha matozo kutoka kwa mtoa huduma wako."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Washa matumizi ya data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Data ya 2G-3G imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Data ya 4G imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Data ya simu ya mkononi imesitishwa"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Data imesitishwa"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Kwa sababu ulifikia kiwango cha juu cha data kilichowekwa, kifaa kimesitisha matumizi ya data katika awamu hii iliyosalia.\n\n Kuendelea kunaweza kusababisha malipo kwa mtoa huduma wako."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Endelea"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Hakuna muunganisho wa mtandao"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Mtandao-hewa umeunganishwa"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Inatafuta GPS"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index c9a7459..b716bda 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"திற"</string>
     <string name="phone_label" msgid="2320074140205331708">"ஃபோனைத் திற"</string>
     <string name="camera_label" msgid="7261107956054836961">"கேமராவைத் திற"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"உள்ளீட்டு முறையை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"பொருந்துமாறு அளவை மாற்றும் பொத்தான்."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"சிறியதிலிருந்து பெரிய திரைக்கு அளவை மாற்றும்."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"புளூடூத் இணைக்கப்பட்டது."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"மொபைல் ஹாட்ஸ்பாட் இயக்கப்பட்டது."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"திரையை அனுப்புதல் நிறுத்தப்பட்டது."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"திரை பிரகாசம்"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"செல்லுலார் தரவு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"தரவு இணைப்பு முடக்கப்பட்டது"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"அமைத்த வரம்பை மீறிவிட்டதால், சாதனம் தரவு இணைப்பை முடக்கியது.\n\nஇதை மீண்டும் இயக்கினால், மொபைல் நிறுவனம் விதிக்கும் கட்டணங்கள் பொருந்தலாம்."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"தரவு இணைப்பை இயக்கு"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G டேட்டா இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G டேட்டா இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"செல்லுலார் தரவு இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"தரவு இடைநிறுத்தப்பட்டது"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"அமைக்கப்பட்ட தரவின் வரம்பை அடைந்துவிட்டதால், இந்தச் சுழற்சியின் மீதமுள்ள நாட்களுக்கான தரவுப் பயன்பாட்டைச் சாதனம் இடைநிறுத்தியுள்ளது.\n\nமீண்டும் தொடங்குவது, மொபைல் நிறுவனக் கட்டணங்களுக்கு உட்படுத்தலாம்."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"மீண்டும் தொடங்கு"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"இணைய இணைப்பு இல்லை"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"வைஃபை இணைக்கப்பட்டது"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS ஐத் தேடுகிறது"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 481acc3..97ea24c 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"అన్‌లాక్ చేయి"</string>
     <string name="phone_label" msgid="2320074140205331708">"ఫోన్‌ను తెరువు"</string>
     <string name="camera_label" msgid="7261107956054836961">"కెమెరాను తెరువు"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ఇన్‌పుట్ పద్ధతి మార్చే బటన్."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"అనుకూలత జూమ్ బటన్."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"చిన్న స్క్రీన్ నుండి పెద్దదానికి జూమ్ చేయండి."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"మొబైల్ హాట్‌స్పాట్ ఆన్ చేయబడింది."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"స్క్రీన్ ప్రసారం ఆపివేయబడింది."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ప్రదర్శన ప్రకాశం"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"సెల్యూలార్ డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"డేటా ఆఫ్‌లో ఉంది"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"మీ పరికరం మీరు సెట్ చేసిన పరిమితిని చేరుకున్నందున డేటాను ఆఫ్ చేసింది.\n\nదీన్ని తిరిగి ఆన్ చేయడం వలన మీ క్యారియర్‌ను బట్టి ఛార్జీలు పడవచ్చు."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"డేటాను ఆన్ చేయి"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"సెల్యులార్ డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"డేటా పాజ్ చేయబడింది"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"మీ సెట్ చేయబడిన డేటా పరిమితిని చేరుకున్నందున పరికరం ఈ సైకిల్‌లో మిగిలిన భాగానికి డేటా వినియోగాన్ని పాజ్ చేసింది.\n\nపునఃప్రారంభించడం వలన మీ క్యారియర్ ఛార్జీలు విధించవచ్చు."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"పునఃప్రారంభించు"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi కనెక్ట్ చేయబడింది"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS కోసం శోధిస్తోంది"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 2aab5ff..66b26db 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"ปลดล็อก"</string>
     <string name="phone_label" msgid="2320074140205331708">"เปิดโทรศัพท์"</string>
     <string name="camera_label" msgid="7261107956054836961">"เปิดกล้อง"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"ปุ่มสลับวิธีการป้อนข้อมูล"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"ปุ่มซูมที่ใช้งานร่วมกันได้"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"ซูมหน้าจอให้มีขนาดใหญ่ขึ้น"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"เชื่อมต่อบลูทูธแล้ว"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"เปิดฮอตสปอตเคลื่อนที่แล้ว"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"หยุดการส่งหน้าจอแล้ว"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ความสว่างของหน้าจอ"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"ข้อมูล 2G-3G ปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"ข้อมูล 4G ปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"ข้อมูลมือถือปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ข้อมูลปิดอยู่"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"อุปกรณ์ของคุณปิดการใช้ข้อมูลเนื่องจากถึงขีดจำกัดที่คุณตั้งค่าไว้\n\nผู้ให้บริการอาจเรียกเก็บเงินหากเปิดใช้อีกครั้ง"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"เปิดใช้ข้อมูล"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"หยุดการใช้ข้อมูล 2G-3G ชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"หยุดการใช้ข้อมูล 4G ชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"หยุดการใช้ข้อมูลมือถือชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"หยุดการใช้ข้อมูลชั่วคราวแล้ว"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"เนื่องจากใช้งานข้อมูลถึงขีดจำกัดที่กำหนดไว้แล้ว อุปกรณ์จึงหยุดการใช้งานข้อมูลไว้ชั่วคราวตลอดระยะเวลาที่เหลือของรอบนี้\n\nการทำให้กลับมาทำงานอีกครั้งอาจทำให้เกิดค่าใช้จ่ายจากผู้ให้บริการ"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"บันทึกต่อ"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"ไม่มีอินเทอร์เน็ต"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"เชื่อมต่อ WiFi แล้ว"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"กำลังค้นหา GPS"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 5a36fb2..95d16d0 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"i-unlock"</string>
     <string name="phone_label" msgid="2320074140205331708">"buksan ang telepono"</string>
     <string name="camera_label" msgid="7261107956054836961">"buksan ang camera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Ilipat ang button na pamamaraan ng pag-input."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Button ng zoom ng pagiging tugma."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Mag-zoom nang mas maliit sa mas malaking screen."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Nakakonekta ang Bluetooth."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Na-on ang mobile hotspot."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Itinigil ang pagka-cast sa screen."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Liwanag ng display"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Naka-off ang 2G-3G data"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Naka-off ang 4G data"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Naka-off ang cellular data"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Naka-off ang data"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Ini-off ng device mo ang data dahil naabot na nito ang limitasyong iyong itinakda.\n\nAng muling pag-o-on dito ay maaaring humantong sa mga singiling magmumula sa iyong carrier."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"I-on ang data"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Naka-pause ang 2G-3G data"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Naka-pause ang 4G data"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Naka-pause ang cellular data"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Naka-pause ang data"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Dahil naabot ang iyong nakatakdang limitasyon sa data, na-pause ng device ang paggamit ng data para sa nalalabing bahagi ng cycle na ito.\n\nMaaaring makakuha ng mga singilin mula sa iyong carrier ang pagpapatuloy."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Ipagpatuloy"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Walang koneksyon sa Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"nakakonekta ang Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Naghahanap ng GPS"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 0ae1e14..10ca6fe 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"kilidi aç"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefonu aç"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamerayı aç"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Giriş yöntemini değiştirme düğmesi."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Uyumluluk zum düğmesi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Daha büyük ekrana daha küçük yakınlaştır."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth bağlandı."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil hotspot açıldı."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekran yayını durduruldu."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran parlaklığı"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Hücresel veri kapalı"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Veri kullanımı kapalı"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Ayarladığınız sınıra erişildiğinden cihazınız veri kullanımını kapattı.\n\nVeri kullanımını tekrar açmanız operatörünüzün ek ödemeler almasına neden olabilir."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Veri kullanımını aç"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Hücresel veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Veri kullanımı duraklatıldı"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ayarlanmış olan veri sınırınıza ulaşıldığından, bu dönemin kalan süresi için cihazda veri kullanımı duraklatıldı.\n\nVeri kullanımını devam ettirmek, operatörünüzün sizden ödeme almasına neden olabilir."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Devam ettir"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"İnternet bağlantısı yok"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Kablosuz bağlandı"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS aranıyor"</string>
@@ -369,14 +368,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"Ayarlardan etkinleştirdiğiniz bir sonraki sefer tekrar görünür."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Gizle"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olmak istiyor."</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"İzin ver"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Reddet"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> ses denetimi iletişim kutusu olarak ayarlandı"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"Orijinali geri yüklemek için dokunun."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index ccecdba..ef6c28d 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -90,7 +90,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"розблокувати"</string>
     <string name="phone_label" msgid="2320074140205331708">"відкрити телефон"</string>
     <string name="camera_label" msgid="7261107956054836961">"відкрити камеру"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Кнопка перемикання методу введення."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Кнопка масштабування сумісності."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Збільшення екрана."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth під’єднано."</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Мобільну точку доступу ввімкнено."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Трансляцію екрана зупинено."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Яскравість дисплея"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Дані 2G–3G вимкнено"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Дані 4G вимкнено"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Мобільні дані вимкнено"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Дані вимкнено"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Пристрій вимкнув передавання даних, оскільки перевищено встановлений вами ліміт.\n\nЯкщо передавання даних знову ввімкнути, оператор може стягувати додаткову плату."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Увімкнути дані"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"Передавання даних 2G–3G призупинено"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"Передавання даних 4G призупинено"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Передавання мобільних даних призупинено"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Передавання даних призупинено"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Пристрій призупинив передавання даних до кінця цього циклу, оскільки ваш ліміт перевищено.\n\nЯкщо ви відновите передавання даних, оператор може стягувати додаткову плату."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Відновити"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Немає з’єднання"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi під’єднано"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Виконується пошук GPS-сигналу"</string>
@@ -371,9 +370,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"З’явиться знову, коли ви ввімкнете його в налаштуваннях."</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"Сховати"</string>
-    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> може стати діалоговим вікном налаштування гучності."</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"Призначити додаток <xliff:g id="APP_NAME">%1$s</xliff:g> регулятором гучності?"</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"Дозволити"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"Відхилити"</string>
-    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> – діалогове вікно налаштування гучності"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> призначено регулятором гучності"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Торкніться, щоб відновити оригінал."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 51180fb..ec66ac4 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"غیر مقفل کریں"</string>
     <string name="phone_label" msgid="2320074140205331708">"فون کھولیں"</string>
     <string name="camera_label" msgid="7261107956054836961">"کیمرا کھولیں"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"اندراج کا طریقہ سوئچ کرنے کا بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"مطابقت پذیری زوم بٹن۔"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"چھوٹی سے بڑی اسکرین پر زوم کریں۔"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"بلوٹوتھ مربوط ہے۔"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"موبائل ہاٹ اسپاٹ کو آن کر دیا گیا۔"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"اسکرین کو کاسٹ کرنا بند کر دیا۔"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"ڈسپلے کی چمک"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"‏2G-3G ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"‏4G ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"سیلولر ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"ڈیٹا آف ہے"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"آپ کے آلہ نے ڈیٹا کو آف کر دیا کیونکہ یہ آپ کی متعینہ حد کو پہنچ گیا۔\n\nاسے دوبارہ آن کرنے سے آپ کے کیریئر کی جانب سے چارجز عائد ہو سکتے ہیں۔"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"ڈیٹا آن کریں"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"‏2G-3G ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"‏4G ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"سیلولر ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"ڈیٹا موقوف کر دیا گیا"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"چونکہ آپ کی سیٹ کردہ ڈیٹا کی حد تک پہنچ گیا، لہذا آلہ نے اس سائیکل کے بقیہ حصے کیلئے ڈیٹا کے استعمال کو موقوف کر دیا ہے۔\n\nدوبارہ شروع کرنے سے آپ کے کیریئر سے چارجز لگ سکتے ہیں۔"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"دوبارہ شروع کریں"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"کوئی انٹرنیٹ کنکشن نہیں"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"‏Wi-Fi مربوط ہے"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"‏GPS کی تلاش کر رہا ہے"</string>
@@ -369,14 +368,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"اگلی بار جب آپ اسے ترتیبات میں آن کریں گے تو یہ ظاہر ہوگی۔"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"چھپائیں"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ بننا چاہتی ہے۔"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"اجازت دیں"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"مسترد کریں"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> والیوم ڈائلاگ ہے"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"اصل کو بحال کرنے کیلئے ٹچ کریں۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 2e1f94f..439adcf 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"qulfdan chiqarish"</string>
     <string name="phone_label" msgid="2320074140205331708">"telefonni ochish"</string>
     <string name="camera_label" msgid="7261107956054836961">"kamerani ochish"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Kiritish uslubi tugmasini almashtirish."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Kattalashtirish tugmasi mosligi."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Kattaroq ekran uchun kichikroqni kattalashtirish."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ulandi."</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Mobil ulanish nuqtasi yoqildi."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ekranni translatsiya qilish to‘xtadi."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Ekran yorqinligi"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G/3G internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Mobil internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Internet o‘chirib qo‘yildi"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Siz o‘rnatgan chegaraga yetib kelgani tufayli qurilmangizda internet o‘chirib qo‘yildi.\n\nUni qayta yoqishingiz mumkin, biroq buning uchun aloqa operatoringiz qo‘shimcha haq olishi mumkin."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Internetni yoqish"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G internet to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G internet to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Mobil internetdan foydalanish to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Internetdan foydalanish to‘xtatib qo‘yildi"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Siz o‘rnatgan mobil internet chekloviga yetgani bois joriy hisob-kitob davrining qolgan muddati uchun mobil internetdan foydalanish vaqtinchalik to‘xtatib qo‘yildi.\n\nAgar internetdan foydalanishni davom ettirsangiz, buning uchun uyali aloqa operatoringiz ortiqcha haq talab qilishi mumkin."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Davom etish"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Internetga ulanmagan"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi ulandi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"GPS qidirilmoqda"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index d3e7a14..a3acbd4 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"mở khóa"</string>
     <string name="phone_label" msgid="2320074140205331708">"mở điện thoại"</string>
     <string name="camera_label" msgid="7261107956054836961">"mở máy ảnh"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Nút chuyển phương thức nhập."</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Nút thu phóng khả năng tương thích."</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Thu phóng màn hình lớn hơn hoặc nhỏ hơn."</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Đã kết nối bluetooth."</string>
@@ -201,12 +200,18 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"Đã bật điểm phát sóng di động."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Đã ngừng truyền màn hình."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Độ sáng màn hình"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Dữ liệu 2G-3G bị tắt"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Dữ liệu 4G bị tắt"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Dữ liệu di động bị tắt"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Dữ liệu bị tắt"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Thiết bị của bạn đã tắt dữ liệu do đã đạt đến giới hạn bạn đã đặt.\n\nViệc bật lại dữ liệu có thể dẫn tới các khoản phí từ nhà cung cấp dịch vụ của bạn."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Bật dữ liệu"</string>
+    <!-- no translation found for data_usage_disabled_dialog_3g_title (5281770593459841889) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_4g_title (1601769736881078016) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_mobile_title (4651001290947318931) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_title (3932437232199671967) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog (8453242888903772524) -->
+    <skip />
+    <!-- no translation found for data_usage_disabled_dialog_enable (1412395410306390593) -->
+    <skip />
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Ko có k.nối Internet"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Đã kết nối Wi-Fi"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Đang tìm kiếm GPS"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 31f0a4d..1c39be4 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解锁"</string>
     <string name="phone_label" msgid="2320074140205331708">"打开电话"</string>
     <string name="camera_label" msgid="7261107956054836961">"打开相机"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"输入法切换按钮。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"兼容性缩放按钮。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"将小屏幕的图片放大在较大屏幕上显示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"蓝牙已连接。"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"移动热点已开启。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"屏幕投射已停止。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"屏幕亮度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"移动数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"数据网络已关闭"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"由于数据流量已达到您所设置的上限,因此您的设备已关闭数据网络。\n\n如果重新开启数据网络,那么您的运营商可能会向您收取相应费用。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"开启数据网络"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G 数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G 数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"移动数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"数据网络已暂停使用"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由于使用的数据流量已达到您所设置的上限,因此您的设备已暂停在此周期的剩余时间内使用数据流量。\n\n如果恢复数据流量使用,您的运营商可能会向您收取相应费用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢复"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"未连接互联网"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"已连接到WLAN网络"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜索GPS"</string>
@@ -371,14 +370,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"要隐藏“<xliff:g id="TILE_LABEL">%1$s</xliff:g>”吗?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下次在设置中将其开启后,此快捷设置条目将会重新显示。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隐藏"</string>
-    <!-- no translation found for volumeui_prompt_message (918680947433389110) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_allow (7954396902482228786) -->
-    <skip />
-    <!-- no translation found for volumeui_prompt_deny (5720663643411696731) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_title (4906770126345910955) -->
-    <skip />
-    <!-- no translation found for volumeui_notification_text (1826889705095768656) -->
-    <skip />
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”请求用作音量控制对话框。"</string>
+    <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允许"</string>
+    <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒绝"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"“<xliff:g id="APP_NAME">%1$s</xliff:g>”已用作音量控制对话框"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"触摸即可恢复原始设置。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index a352a23..d97a7ba 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解鎖"</string>
     <string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
     <string name="camera_label" msgid="7261107956054836961">"開啟相機"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"流動熱點已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"顯示光暗度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"流動數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"數據流量已達到您所設定的上限,因此裝置關閉了數據連線。\n\n若重新開啟數據連線,流動網絡供應商可能會向您收費。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"開啟數據連線"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停流動數據"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據功能"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於您已達到設定的數據用量上限,裝置已暫停使用數據,直到週期結束。 \n\n如果恢復,流動網絡供應商可能會向您收取費用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有互聯網連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
@@ -371,9 +370,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"下一次您在設定開啟它時,它將再次出現。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
-    <string name="volumeui_prompt_message" msgid="918680947433389110">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」想成為音量對話。"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」想成為音量對話框。"</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允許"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
-    <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」為音量對話框"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸即可復原。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 7cef5aa..bcf9bd1 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"解除鎖定"</string>
     <string name="phone_label" msgid="2320074140205331708">"開啟電話"</string>
     <string name="camera_label" msgid="7261107956054836961">"開啟攝影機"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"切換輸入法按鈕。"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"相容性縮放按鈕。"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"將較小螢幕的畫面放大在較大螢幕上顯示。"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"藍牙連線已建立。"</string>
@@ -203,12 +202,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"可攜式無線基地台已開啟。"</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"已停止投放螢幕。"</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"螢幕亮度"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"2G-3G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"4G 數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"行動數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"數據連線已關閉"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"數據流量已達您所設定的上限,因此裝置關閉了數據連線。\n\n如果重新開啟數據連線,行動通訊業者可能會向您收費。"</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"開啟數據連線"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"已暫停 2G-3G 數據連線"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"已暫停 4G 數據連線"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"已暫停行動數據連線"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"已暫停數據連線"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"由於數據用量已達設定上限,裝置在這個週期的剩餘時間將暫停使用數據連線。\n\n如果恢復使用,行動通訊業者可能會向您收取相關費用。"</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"恢復連線"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"沒有網際網路連線"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"Wi-Fi 已連線"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"正在搜尋 GPS"</string>
@@ -371,9 +370,9 @@
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
     <string name="quick_settings_reset_confirmation_message" msgid="2235970126803317374">"只要在設定頁面中重新啟用,就能再次看到快捷設定選項。"</string>
     <string name="quick_settings_reset_confirmation_button" msgid="2660339101868367515">"隱藏"</string>
-    <string name="volumeui_prompt_message" msgid="918680947433389110">"<xliff:g id="APP_NAME">%1$s</xliff:g> 想成為預設的音量控制對話方塊。"</string>
+    <string name="volumeui_prompt_message" msgid="918680947433389110">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」要求成為預設的音量控制對話方塊。"</string>
     <string name="volumeui_prompt_allow" msgid="7954396902482228786">"允許"</string>
     <string name="volumeui_prompt_deny" msgid="5720663643411696731">"拒絕"</string>
-    <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> 現在是預設的音量控制對話方塊。"</string>
-    <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸即可還原為原始的音量控制對話方塊。"</string>
+    <string name="volumeui_notification_title" msgid="4906770126345910955">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」現在是預設的音量控制對話方塊。"</string>
+    <string name="volumeui_notification_text" msgid="1826889705095768656">"輕觸這裡即可恢復原始設定。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 7bb54d6..7f3ac02 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -88,7 +88,6 @@
     <string name="unlock_label" msgid="8779712358041029439">"vula"</string>
     <string name="phone_label" msgid="2320074140205331708">"vula ifoni"</string>
     <string name="camera_label" msgid="7261107956054836961">"vula ikhamera"</string>
-    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">"Vula indlela yokungena yenkinobho"</string>
     <string name="accessibility_compatibility_zoom_button" msgid="8461115318742350699">"Inkinobho evumelekile yokusondeza"</string>
     <string name="accessibility_compatibility_zoom_example" msgid="4220687294564945780">"Sondeza kancane esikrinini esikhudlwana"</string>
     <string name="accessibility_bluetooth_connected" msgid="2707027633242983370">"Bluetooth ixhunyiwe"</string>
@@ -201,12 +200,12 @@
     <string name="accessibility_quick_settings_hotspot_changed_on" msgid="2890951609226476206">"I-hotspot ivuliwe."</string>
     <string name="accessibility_casting_turned_off" msgid="1430668982271976172">"Ukusakaza kwesikrini kumisiwe."</string>
     <string name="accessibility_brightness" msgid="8003681285547803095">"Bonisa ukukhanya"</string>
-    <string name="data_usage_disabled_dialog_3g_title" msgid="2626865386971800302">"Idatha ye-2G-3G ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_4g_title" msgid="4629078114195977196">"Idatha ye-4G ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_mobile_title" msgid="5793456071535876132">"Idatha yeselula ivaliwe"</string>
-    <string name="data_usage_disabled_dialog_title" msgid="8723412000355709802">"Idatha ivaliwe"</string>
-    <string name="data_usage_disabled_dialog" msgid="6468718338038876604">"Idivayisi yakho ivale idatha ngoba ifinyelele umkhawulo owubekile.\n\nUkuyivula futhi kungaholela ezindlekweni kusuka kunkampani yakho yenethiwekhi."</string>
-    <string name="data_usage_disabled_dialog_enable" msgid="5538068036107372895">"Vula idatha"</string>
+    <string name="data_usage_disabled_dialog_3g_title" msgid="5281770593459841889">"2G-3G idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog_4g_title" msgid="1601769736881078016">"4G idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog_mobile_title" msgid="4651001290947318931">"Idatha yeselula imisiwe"</string>
+    <string name="data_usage_disabled_dialog_title" msgid="3932437232199671967">"Idatha imisiwe"</string>
+    <string name="data_usage_disabled_dialog" msgid="8453242888903772524">"Ngoba umkhawulo wakho wedatha osethiwe ufinyelelwe, idivayisi imise kancane ukusetshenziswa kwedatha ngesikhumbuzi salo mjikelezo.\n\nUkuqhuba futhi kungaholela kuzindleko kusuka kwinkampani yakho yenethiwekhi."</string>
+    <string name="data_usage_disabled_dialog_enable" msgid="1412395410306390593">"Qalisa kabusha"</string>
     <string name="status_bar_settings_signal_meter_disconnected" msgid="1940231521274147771">"Alukho uxhumano lwe-Inthanethi"</string>
     <string name="status_bar_settings_signal_meter_wifi_nossid" msgid="6557486452774597820">"I-Wi-Fi ixhunyiwe"</string>
     <string name="gps_notification_searching_text" msgid="8574247005642736060">"Isesha i-GPS"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 808ded5..d8b6a82 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -217,8 +217,6 @@
     <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
     <string name="camera_label">open camera</string>
 
-    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_ime_switch_button">Switch input method button.</string>
     <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f3d214f..1cf0129 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1300,6 +1300,8 @@
         @Override
         public void run() {
             try {
+                mStatusBarKeyguardViewManager.keyguardGoingAway();
+
                 // Don't actually hide the Keyguard at the moment, wait for window
                 // manager until it tells us it's safe to do so with
                 // startKeyguardExitAnimation.
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 25bab17..c23f45d 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -114,7 +114,9 @@
     @Override
     protected void onDestroy() {
         super.onDestroy();
-        mDialog.dismiss();
+        if (mDialog != null) {
+            mDialog.dismiss();
+        }
     }
 
     @Override
@@ -128,7 +130,9 @@
             Log.e(TAG, "Error granting projection permission", e);
             setResult(RESULT_CANCELED);
         } finally {
-            mDialog.dismiss();
+            if (mDialog != null) {
+                mDialog.dismiss();
+            }
             finish();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b1ac733..e0b4c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -193,8 +193,7 @@
         }
 
         // Start loading tasks according to the load plan
-        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
-        if (stacks.size() == 0) {
+        if (!plan.hasTasks()) {
             loader.preloadTasks(plan, mConfig.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
@@ -203,11 +202,11 @@
         loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
-        boolean hasTasks = plan.hasTasks();
-        if (hasTasks) {
+        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
+        mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
+        if (!mConfig.launchedWithNoRecentTasks) {
             mRecentsView.setTaskStacks(stacks);
         }
-        mConfig.launchedWithNoRecentTasks = !hasTasks;
 
         // Create the home intent runnable
         Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
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 2318319..21975b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -879,7 +879,7 @@
 
                     // Start the focus animation when alt-tabbing
                     if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
-                        TaskView tv = taskViews.get(mFocusedTaskIndex);
+                        TaskView tv = getChildViewForTask(mStack.getTasks().get(mFocusedTaskIndex));
                         if (tv != null) {
                             tv.setFocusedTask(true);
                         }
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 b827acc..81e960a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -32,12 +32,10 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.widget.FrameLayout;
@@ -104,11 +102,10 @@
         });
 
         // Load the dismiss resources
-        Resources res = context.getResources();
-        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
-        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
+        mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
         mDismissContentDescription =
-                res.getString(R.string.accessibility_recents_item_will_be_dismissed);
+                context.getString(R.string.accessibility_recents_item_will_be_dismissed);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
@@ -283,23 +280,26 @@
         }
 
         if (focused) {
+            int currentColor = mBackgroundColor;
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
+                    new int[] {},
                     new int[] { android.R.attr.state_enabled },
                     new int[] { android.R.attr.state_pressed }
             };
             int[] newStates = new int[]{
+                    0,
                     android.R.attr.state_enabled,
                     android.R.attr.state_pressed
             };
             int[] colors = new int[] {
+                    currentColor,
                     secondaryColor,
                     secondaryColor
             };
             mBackground.setColor(new ColorStateList(states, colors));
             mBackground.setState(newStates);
             // Pulse the background color
-            int currentColor = mBackgroundColor;
             int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
                     currentColor, lightPrimaryColor);
@@ -326,7 +326,7 @@
 
             mFocusAnimator = new AnimatorSet();
             mFocusAnimator.playTogether(backgroundColor, translation);
-            mFocusAnimator.setStartDelay(750);
+            mFocusAnimator.setStartDelay(150);
             mFocusAnimator.setDuration(750);
             mFocusAnimator.start();
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 0b1b883..8f88e73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -19,6 +19,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.util.Pair;
 
 import com.android.internal.statusbar.IStatusBar;
 import com.android.internal.statusbar.StatusBarIcon;
@@ -57,6 +58,9 @@
     private static final int MSG_NOTIFICATION_LIGHT_OFF     = 16 << MSG_SHIFT;
     private static final int MSG_NOTIFICATION_LIGHT_PULSE   = 17 << MSG_SHIFT;
     private static final int MSG_SHOW_SCREEN_PIN_REQUEST    = 18 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_PENDING     = 19 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_CANCELLED   = 20 << MSG_SHIFT;
+    private static final int MSG_APP_TRANSITION_STARTING    = 21 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -99,6 +103,9 @@
         public void notificationLightOff();
         public void notificationLightPulse(int argb, int onMillis, int offMillis);
         public void showScreenPinningRequest();
+        public void appTransitionPending();
+        public void appTransitionCancelled();
+        public void appTransitionStarting(long startTime, long duration);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -246,6 +253,28 @@
         }
     }
 
+    public void appTransitionPending() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+        }
+    }
+
+    public void appTransitionCancelled() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_PENDING);
+            mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING);
+        }
+    }
+
+    public void appTransitionStarting(long startTime, long duration) {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_APP_TRANSITION_STARTING);
+            mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration))
+                    .sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -328,6 +357,16 @@
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
                     mCallbacks.showScreenPinningRequest();
                     break;
+                case MSG_APP_TRANSITION_PENDING:
+                    mCallbacks.appTransitionPending();
+                    break;
+                case MSG_APP_TRANSITION_CANCELLED:
+                    mCallbacks.appTransitionCancelled();
+                    break;
+                case MSG_APP_TRANSITION_STARTING:
+                    Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
+                    mCallbacks.appTransitionStarting(data.first, data.second);
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 0fc46e9..01aa8d1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -44,7 +44,7 @@
     }
 
     private void draw(Canvas canvas, Drawable drawable) {
-        if (drawable != null) {
+        if (drawable != null && mActualHeight > mClipTopAmount) {
             drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
             drawable.draw(canvas);
         }
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 ece69d3..8aafe52 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -101,7 +101,6 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AccelerateInterpolator;
-import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.PathInterpolator;
@@ -115,7 +114,6 @@
 import com.android.systemui.DemoMode;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
-import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -138,7 +136,6 @@
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.SpeedBumpView;
-import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
@@ -3118,6 +3115,8 @@
                                 mLaunchTransitionFadingAway = false;
                             }
                         });
+                mIconController.appTransitionStarting(SystemClock.uptimeMillis(),
+                        StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
             }
         };
         if (mNotificationPanel.isLaunchTransitionRunning()) {
@@ -3185,16 +3184,31 @@
     }
 
     /**
+     * Notifies the status bar that Keyguard is going away very soon.
+     */
+    public void keyguardGoingAway() {
+
+        // Treat Keyguard exit animation as an app transition to achieve nice transition for status
+        // bar.
+        mIconController.appTransitionPending();
+    }
+
+    /**
      * Notifies the status bar the Keyguard is fading away with the specified timings.
      *
-     * @param delay the animation delay in miliseconds
+     * @param startTime the start time of the animations in uptime millis
+     * @param delay the precalculated animation delay in miliseconds
      * @param fadeoutDuration the duration of the exit animation, in milliseconds
      */
-    public void setKeyguardFadingAway(long delay, long fadeoutDuration) {
+    public void setKeyguardFadingAway(long startTime, long delay, long fadeoutDuration) {
         mKeyguardFadingAway = true;
         mKeyguardFadingAwayDelay = delay;
         mKeyguardFadingAwayDuration = fadeoutDuration;
         mWaitingForKeyguardExit = false;
+        mIconController.appTransitionStarting(
+                startTime + fadeoutDuration
+                        - StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION,
+                StatusBarIconController.DEFAULT_TINT_ANIMATION_DURATION);
         disable(mDisabledUnmodified, true /* animate */);
     }
 
@@ -3210,8 +3224,9 @@
     }
 
     private void updatePublicMode() {
-        setLockscreenPublicMode(mStatusBarKeyguardViewManager.isShowing()
-                && mStatusBarKeyguardViewManager.isSecure(mCurrentUserId));
+        setLockscreenPublicMode(
+                mStatusBarKeyguardViewManager.isShowing() && mStatusBarKeyguardViewManager
+                        .isSecure(mCurrentUserId));
     }
 
     private void updateKeyguardState(boolean goingToFullShade, boolean fromShadeLocked) {
@@ -3638,6 +3653,31 @@
         }
     }
 
+    @Override
+    public void appTransitionPending() {
+
+        // Use own timings when Keyguard is going away, see keyguardGoingAway and
+        // setKeyguardFadingAway
+        if (!mKeyguardFadingAway) {
+            mIconController.appTransitionPending();
+        }
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+        mIconController.appTransitionCancelled();
+    }
+
+    @Override
+    public void appTransitionStarting(long startTime, long duration) {
+
+        // Use own timings when Keyguard is going away, see keyguardGoingAway and
+        // setKeyguardFadingAway
+        if (!mKeyguardFadingAway) {
+            mIconController.appTransitionStarting(startTime, duration);
+        }
+    }
+
     private final class ShadeUpdates {
         private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
         private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 5622993..3bdf94a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -16,11 +16,15 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Color;
 import android.graphics.PorterDuff;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.AnimationUtils;
@@ -48,9 +52,12 @@
  */
 public class StatusBarIconController {
 
+    public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
+
     private Context mContext;
     private PhoneStatusBar mPhoneStatusBar;
     private Interpolator mLinearOutSlowIn;
+    private Interpolator mFastOutSlowIn;
     private DemoStatusIcons mDemoStatusIcons;
     private NotificationColorUtil mNotificationColorUtil;
 
@@ -69,6 +76,23 @@
 
     private int mIconTint = Color.WHITE;
 
+    private boolean mTransitionPending;
+    private boolean mTintChangePending;
+    private int mPendingIconTint;
+    private ValueAnimator mTintAnimator;
+
+    private final Handler mHandler;
+    private boolean mTransitionDeferring;
+    private long mTransitionDeferringStartTime;
+    private long mTransitionDeferringDuration;
+
+    private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
+        @Override
+        public void run() {
+            mTransitionDeferring = false;
+        }
+    };
+
     public StatusBarIconController(Context context, View statusBar, View keyguardStatusBar,
             PhoneStatusBar phoneStatusBar) {
         mContext = context;
@@ -86,6 +110,9 @@
         mClock = (TextView) statusBar.findViewById(R.id.clock);
         mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.linear_out_slow_in);
+        mFastOutSlowIn = AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.fast_out_slow_in);
+        mHandler = new Handler();
         updateResources();
     }
 
@@ -268,10 +295,49 @@
     }
 
     public void setIconTint(int tint) {
+        if (mTransitionPending) {
+            deferIconTintChange(tint);
+        } else if (mTransitionDeferring) {
+            animateIconTint(tint,
+                    Math.max(0, mTransitionDeferringStartTime - SystemClock.uptimeMillis()),
+                    mTransitionDeferringDuration);
+        } else {
+            animateIconTint(tint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+        }
+    }
+
+    private void animateIconTint(int targetTint, long delay, long duration) {
+        if (mTintAnimator != null) {
+            mTintAnimator.cancel();
+        }
+        if (mIconTint == targetTint) {
+            return;
+        }
+        mTintAnimator = ValueAnimator.ofArgb(mIconTint, targetTint);
+        mTintAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                setIconTintInternal((Integer) animation.getAnimatedValue());
+            }
+        });
+        mTintAnimator.setDuration(duration);
+        mTintAnimator.setStartDelay(delay);
+        mTintAnimator.setInterpolator(mFastOutSlowIn);
+        mTintAnimator.start();
+    }
+    private void setIconTintInternal(int tint) {
         mIconTint = tint;
         applyIconTint();
     }
 
+    private void deferIconTintChange(int tint) {
+        if (mTintChangePending && tint == mPendingIconTint) {
+            return;
+        }
+        mTintChangePending = true;
+        mPendingIconTint = tint;
+    }
+
     private void applyIconTint() {
         for (int i = 0; i < mStatusIcons.getChildCount(); i++) {
             StatusBarIconView v = (StatusBarIconView) mStatusIcons.getChildAt(i);
@@ -305,4 +371,36 @@
         v.setTag(R.id.icon_is_grayscale, grayscale);
         return grayscale;
     }
+
+    public void appTransitionPending() {
+        mTransitionPending = true;
+    }
+
+    public void appTransitionCancelled() {
+        if (mTransitionPending && mTintChangePending) {
+            mTintChangePending = false;
+            animateIconTint(mPendingIconTint, 0 /* delay */, DEFAULT_TINT_ANIMATION_DURATION);
+        }
+        mTransitionPending = false;
+    }
+
+    public void appTransitionStarting(long startTime, long duration) {
+        if (mTransitionPending && mTintChangePending) {
+            mTintChangePending = false;
+            animateIconTint(mPendingIconTint,
+                    Math.max(0, startTime - SystemClock.uptimeMillis()),
+                    duration);
+
+        } else if (mTransitionPending) {
+
+            // If we don't have a pending tint change yet, the change might come in the future until
+            // startTime is reached.
+            mTransitionDeferring = true;
+            mTransitionDeferringStartTime = startTime;
+            mTransitionDeferringDuration = duration;
+            mHandler.removeCallbacks(mTransitionDeferringDoneRunnable);
+            mHandler.postAtTime(mTransitionDeferringDoneRunnable, startTime);
+        }
+        mTransitionPending = false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 19305f3..2f3a159 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -257,7 +257,7 @@
                 }
             });
         } else {
-            mPhoneStatusBar.setKeyguardFadingAway(delay, fadeoutDuration);
+            mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
             boolean staying = mPhoneStatusBar.hideKeyguard();
             if (!staying) {
                 mStatusBarWindowManager.setKeyguardFadingAway(true);
@@ -435,4 +435,8 @@
     public boolean isInputRestricted() {
         return mViewMediatorCallback.isInputRestricted();
     }
+
+    public void keyguardGoingAway() {
+        mPhoneStatusBar.keyguardGoingAway();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
index 0863c86..7ca91a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotController.java
@@ -22,7 +22,6 @@
     boolean isHotspotEnabled();
     boolean isHotspotSupported();
     void setHotspotEnabled(boolean enabled);
-    boolean isProvisioningNeeded();
 
     public interface Callback {
         void onHotspotChanged(boolean enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index 5eff5a6..4bfd528 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -16,45 +16,38 @@
 
 package com.android.systemui.statusbar.policy;
 
-import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
-import android.os.SystemProperties;
 import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Log;
 
+import com.android.settingslib.TetherUtil;
+
 import java.util.ArrayList;
 
 public class HotspotControllerImpl implements HotspotController {
 
     private static final String TAG = "HotspotController";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
-    // Keep these in sync with Settings TetherService.java
-    public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
-    public static final String EXTRA_SET_ALARM = "extraSetAlarm";
-    public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
-    public static final String EXTRA_ENABLE_WIFI_TETHER = "extraEnableWifiTether";
-    // Keep this in sync with Settings TetherSettings.java
-    public static final int WIFI_TETHERING = 0;
+    private static final Intent TETHER_SERVICE_INTENT = new Intent()
+            .putExtra(TetherUtil.EXTRA_ADD_TETHER_TYPE, TetherUtil.TETHERING_WIFI)
+            .putExtra(TetherUtil.EXTRA_SET_ALARM, true)
+            .putExtra(TetherUtil.EXTRA_RUN_PROVISION, true)
+            .putExtra(TetherUtil.EXTRA_ENABLE_WIFI_TETHER, true)
+            .setComponent(TetherUtil.TETHER_SERVICE);
 
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
     private final Receiver mReceiver = new Receiver();
     private final Context mContext;
     private final WifiManager mWifiManager;
-    private final ConnectivityManager mConnectivityManager;
 
     public HotspotControllerImpl(Context context) {
         mContext = context;
         mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
-        mConnectivityManager = (ConnectivityManager)
-                mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
     }
 
     public void addCallback(Callback callback) {
@@ -78,54 +71,17 @@
 
     @Override
     public boolean isHotspotSupported() {
-        final boolean isSecondaryUser = ActivityManager.getCurrentUser() != UserHandle.USER_OWNER;
-        return !isSecondaryUser && mConnectivityManager.isTetheringSupported();
-    }
-
-    @Override
-    public boolean isProvisioningNeeded() {
-        // Keep in sync with other usage of config_mobile_hotspot_provision_app.
-        // TetherSettings#isProvisioningNeeded and
-        // ConnectivityManager#enforceTetherChangePermission
-        String[] provisionApp = mContext.getResources().getStringArray(
-                com.android.internal.R.array.config_mobile_hotspot_provision_app);
-        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)
-                || provisionApp == null) {
-            return false;
-        }
-        return (provisionApp.length == 2);
+        return TetherUtil.isTetheringSupported(mContext);
     }
 
     @Override
     public void setHotspotEnabled(boolean enabled) {
         final ContentResolver cr = mContext.getContentResolver();
         // Call provisioning app which is called when enabling Tethering from Settings
-        if (enabled) {
-            if (isProvisioningNeeded()) {
-                String tetherEnable = mContext.getResources().getString(
-                        com.android.internal.R.string.config_wifi_tether_enable);
-                Intent intent = new Intent();
-                intent.putExtra(EXTRA_ADD_TETHER_TYPE, WIFI_TETHERING);
-                intent.putExtra(EXTRA_SET_ALARM, true);
-                intent.putExtra(EXTRA_RUN_PROVISION, true);
-                intent.putExtra(EXTRA_ENABLE_WIFI_TETHER, true);
-                intent.setComponent(ComponentName.unflattenFromString(tetherEnable));
-                mContext.startServiceAsUser(intent, UserHandle.CURRENT);
-            } else {
-                int wifiState = mWifiManager.getWifiState();
-                if ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
-                        (wifiState == WifiManager.WIFI_STATE_ENABLED)) {
-                    mWifiManager.setWifiEnabled(false);
-                    Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
-                }
-                mWifiManager.setWifiApEnabled(null, true);
-            }
+        if (enabled && TetherUtil.isProvisioningNeeded(mContext)) {
+            mContext.startServiceAsUser(TETHER_SERVICE_INTENT, UserHandle.CURRENT);
         } else {
-            mWifiManager.setWifiApEnabled(null, false);
-            if (Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0) == 1) {
-                mWifiManager.setWifiEnabled(true);
-                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-            }
+            TetherUtil.setWifiTethering(enabled, mContext);
         }
     }
 
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 6f2a392..413c891 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -170,4 +170,16 @@
     @Override
     public void showScreenPinningRequest() {
     }
+
+    @Override
+    public void appTransitionPending() {
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+    }
+
+    @Override
+    public void appTransitionStarting(long startTime, long duration) {
+    }
 }
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index e7487aa..417bfe2 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -938,6 +938,8 @@
 
     long     mDev;
     long     mContext;
+    private boolean mDestroyed = false;
+
     @SuppressWarnings({"FieldCanBeLocal"})
     MessageThread mMessageThread;
 
@@ -1382,6 +1384,38 @@
         nContextFinish();
     }
 
+    private void helpDestroy() {
+        boolean shouldDestroy = false;
+        synchronized(this) {
+            if (!mDestroyed) {
+                shouldDestroy = true;
+                mDestroyed = true;
+            }
+        }
+
+        if (shouldDestroy) {
+            nContextFinish();
+
+            nContextDeinitToClient(mContext);
+            mMessageThread.mRun = false;
+            try {
+                mMessageThread.join();
+            } catch(InterruptedException e) {
+            }
+
+            nContextDestroy();
+
+            nDeviceDestroy(mDev);
+            mDev = 0;
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        helpDestroy();
+        super.finalize();
+    }
+
+
     /**
      * Destroys this RenderScript context.  Once this function is called,
      * using this context or any objects belonging to this context is
@@ -1390,19 +1424,7 @@
      */
     public void destroy() {
         validate();
-        nContextFinish();
-
-        nContextDeinitToClient(mContext);
-        mMessageThread.mRun = false;
-        try {
-            mMessageThread.join();
-        } catch(InterruptedException e) {
-        }
-
-        nContextDestroy();
-
-        nDeviceDestroy(mDev);
-        mDev = 0;
+        helpDestroy();
     }
 
     boolean isAlive() {
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index c8b080e..b4613d6 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.Property;
 import android.util.Slog;
+import android.util.TypedValue;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MagnificationSpec;
@@ -110,7 +111,6 @@
     private static final int STATE_MAGNIFIED_INTERACTION = 4;
 
     private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
-    private static final int MULTI_TAP_TIME_SLOP_ADJUSTMENT = 50;
 
     private static final int MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED = 1;
     private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 2;
@@ -135,9 +135,8 @@
 
     private final AccessibilityManagerService mAms;
 
-    private final int mTapTimeSlop = ViewConfiguration.getTapTimeout();
-    private final int mMultiTapTimeSlop =
-            ViewConfiguration.getDoubleTapTimeout() - MULTI_TAP_TIME_SLOP_ADJUSTMENT;
+    private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
+    private final int mMultiTapTimeSlop;
     private final int mTapDistanceSlop;
     private final int mMultiTapDistanceSlop;
 
@@ -192,6 +191,9 @@
         mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mAms = service;
 
+        mMultiTapTimeSlop = ViewConfiguration.getDoubleTapTimeout()
+                + mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
         mLongAnimationDuration = context.getResources().getInteger(
                 com.android.internal.R.integer.config_longAnimTime);
         mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -481,15 +483,20 @@
         private static final float MIN_SCALE = 1.3f;
         private static final float MAX_SCALE = 5.0f;
 
-        private static final float SCALING_THRESHOLD = 0.3f;
-
         private final ScaleGestureDetector mScaleGestureDetector;
         private final GestureDetector mGestureDetector;
 
+        private final float mScalingThreshold;
+
         private float mInitialScaleFactor = -1;
         private boolean mScaling;
 
         public MagnifiedContentInteractonStateHandler(Context context) {
+            final TypedValue scaleValue = new TypedValue();
+            context.getResources().getValue(
+                    com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
+                    scaleValue, false);
+            mScalingThreshold = scaleValue.getFloat();
             mScaleGestureDetector = new ScaleGestureDetector(context, this);
             mScaleGestureDetector.setQuickScaleEnabled(false);
             mGestureDetector = new GestureDetector(context, this);
@@ -537,7 +544,7 @@
                     mInitialScaleFactor = detector.getScaleFactor();
                 } else {
                     final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
-                    if (Math.abs(deltaScale) > SCALING_THRESHOLD) {
+                    if (Math.abs(deltaScale) > mScalingThreshold) {
                         mScaling = true;
                         return true;
                     }
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 8bd7132..2e84fbe 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -318,6 +318,8 @@
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
+
         BackupManagerService svc = mService;
         if (svc != null) {
             svc.dump(fd, pw, args);
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 912a181..b3b4651 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -626,6 +626,22 @@
                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);
                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);
                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
+
+            } else if ("unplug".equals(args[0])) {
+                if (!mUpdatesStopped) {
+                    mLastBatteryProps.set(mBatteryProps);
+                }
+                mBatteryProps.chargerAcOnline = false;
+                mBatteryProps.chargerUsbOnline = false;
+                mBatteryProps.chargerWirelessOnline = false;
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mUpdatesStopped = true;
+                    processValuesLocked(false);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+
             } else if (args.length == 3 && "set".equals(args[0])) {
                 String key = args[1];
                 String value = args[2];
@@ -662,6 +678,7 @@
                 } catch (NumberFormatException ex) {
                     pw.println("Bad value: " + value);
                 }
+
             } else if (args.length == 1 && "reset".equals(args[0])) {
                 long ident = Binder.clearCallingIdentity();
                 try {
@@ -676,6 +693,7 @@
             } else {
                 pw.println("Dump current battery state, or:");
                 pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
+                pw.println("  unplug");
                 pw.println("  reset");
             }
         }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 77b8b31..895a5c3 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -46,6 +47,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
 
@@ -257,6 +259,9 @@
 
     private void setStringUnchecked(String key, int userId, String value) {
         mStorage.writeKeyValue(key, value, userId);
+        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
+            BackupManager.dataChanged("com.android.providers.settings");
+        }
     }
 
     @Override
@@ -463,6 +468,11 @@
         Secure.LOCK_SCREEN_OWNER_INFO
     };
 
+    private static final String[] SETTINGS_TO_BACKUP = new String[] {
+        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+        Secure.LOCK_SCREEN_OWNER_INFO
+    };
+
     private IMountService getMountService() {
         final IBinder service = ServiceManager.getService("mount");
         if (service != null) {
diff --git a/services/core/java/com/android/server/MidiService.java b/services/core/java/com/android/server/MidiService.java
index 38f1cb8..04911fa 100644
--- a/services/core/java/com/android/server/MidiService.java
+++ b/services/core/java/com/android/server/MidiService.java
@@ -17,10 +17,10 @@
 package com.android.server;
 
 import android.content.Context;
-import android.midi.IMidiDeviceServer;
-import android.midi.IMidiListener;
-import android.midi.IMidiManager;
-import android.midi.MidiDeviceInfo;
+import android.media.midi.IMidiDeviceServer;
+import android.media.midi.IMidiListener;
+import android.media.midi.IMidiManager;
+import android.media.midi.MidiDeviceInfo;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 50820ff..008d718 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2256,31 +2256,33 @@
             if (MONITOR_CPU_USAGE &&
                     mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
                 mLastCpuTime.set(now);
-                haveNewCpuStats = true;
                 mProcessCpuTracker.update();
-                //Slog.i(TAG, mProcessCpu.printCurrentState());
-                //Slog.i(TAG, "Total CPU usage: "
-                //        + mProcessCpu.getTotalCpuPercent() + "%");
+                if (mProcessCpuTracker.hasGoodLastStats()) {
+                    haveNewCpuStats = true;
+                    //Slog.i(TAG, mProcessCpu.printCurrentState());
+                    //Slog.i(TAG, "Total CPU usage: "
+                    //        + mProcessCpu.getTotalCpuPercent() + "%");
 
-                // Slog the cpu usage if the property is set.
-                if ("true".equals(SystemProperties.get("events.cpu"))) {
-                    int user = mProcessCpuTracker.getLastUserTime();
-                    int system = mProcessCpuTracker.getLastSystemTime();
-                    int iowait = mProcessCpuTracker.getLastIoWaitTime();
-                    int irq = mProcessCpuTracker.getLastIrqTime();
-                    int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
-                    int idle = mProcessCpuTracker.getLastIdleTime();
+                    // Slog the cpu usage if the property is set.
+                    if ("true".equals(SystemProperties.get("events.cpu"))) {
+                        int user = mProcessCpuTracker.getLastUserTime();
+                        int system = mProcessCpuTracker.getLastSystemTime();
+                        int iowait = mProcessCpuTracker.getLastIoWaitTime();
+                        int irq = mProcessCpuTracker.getLastIrqTime();
+                        int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
+                        int idle = mProcessCpuTracker.getLastIdleTime();
 
-                    int total = user + system + iowait + irq + softIrq + idle;
-                    if (total == 0) total = 1;
+                        int total = user + system + iowait + irq + softIrq + idle;
+                        if (total == 0) total = 1;
 
-                    EventLog.writeEvent(EventLogTags.CPU,
-                            ((user+system+iowait+irq+softIrq) * 100) / total,
-                            (user * 100) / total,
-                            (system * 100) / total,
-                            (iowait * 100) / total,
-                            (irq * 100) / total,
-                            (softIrq * 100) / total);
+                        EventLog.writeEvent(EventLogTags.CPU,
+                                ((user+system+iowait+irq+softIrq) * 100) / total,
+                                (user * 100) / total,
+                                (system * 100) / total,
+                                (iowait * 100) / total,
+                                (irq * 100) / total,
+                                (softIrq * 100) / total);
+                    }
                 }
             }
 
@@ -2289,8 +2291,10 @@
             synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
                     if (haveNewCpuStats) {
-                        if (mOnBattery) {
-                            int perc = bstats.startAddingCpuLocked();
+                        final int perc = bstats.startAddingCpuLocked();
+                        if (perc >= 0) {
+                            int remainUTime = 0;
+                            int remainSTime = 0;
                             int totalUTime = 0;
                             int totalSTime = 0;
                             final int N = mProcessCpuTracker.countStats();
@@ -2302,17 +2306,18 @@
                                 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
                                 int otherUTime = (st.rel_utime*perc)/100;
                                 int otherSTime = (st.rel_stime*perc)/100;
-                                totalUTime += otherUTime;
-                                totalSTime += otherSTime;
+                                remainUTime += otherUTime;
+                                remainSTime += otherSTime;
+                                totalUTime += st.rel_utime;
+                                totalSTime += st.rel_stime;
                                 if (pr != null) {
                                     BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
                                                 pr.info.uid, pr.processName);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
                                     pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
@@ -2320,13 +2325,19 @@
                                         st.batteryStats = ps = bstats.getProcessStatsLocked(
                                                 bstats.mapUid(st.uid), st.name);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
                                 }
                             }
-                            bstats.finishAddingCpuLocked(perc, totalUTime,
-                                    totalSTime, cpuSpeedTimes);
+                            final int userTime = mProcessCpuTracker.getLastUserTime();
+                            final int systemTime = mProcessCpuTracker.getLastSystemTime();
+                            final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime();
+                            final int irqTime = mProcessCpuTracker.getLastIrqTime();
+                            final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime();
+                            final int idleTime = mProcessCpuTracker.getLastIdleTime();
+                            bstats.finishAddingCpuLocked(perc, remainUTime,
+                                    remainSTime, totalUTime, totalSTime, userTime, systemTime,
+                                    iowaitTime, irqTime, softIrqTime, idleTime, cpuSpeedTimes);
                         }
                     }
                 }
@@ -2387,8 +2398,7 @@
             } else {
                 finishRunningVoiceLocked();
             }
-            mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity");
-            if (r != null) {
+            if (r != null && mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
                 mWindowManager.setFocusedApp(r.appToken, true);
             }
             applyUpdateLockStateLocked(r);
@@ -2412,6 +2422,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked(null);
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
+                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
                 }
             }
         }
@@ -7771,7 +7782,7 @@
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnail()");
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id);
+            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, false);
             if (tr != null) {
                 return tr.getTaskThumbnailLocked();
             }
@@ -7884,7 +7895,7 @@
     @Override
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (this) {
-            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, false);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
@@ -7898,6 +7909,25 @@
     }
 
     @Override
+    public void resizeTask(int taskId, Rect bounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizeTask()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, true);
+                if (task == null) {
+                    Slog.w(TAG, "resizeTask: taskId=" + taskId + " not found");
+                    return;
+                }
+                mStackSupervisor.resizeTaskLocked(task, bounds);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public Bitmap getTaskDescriptionIcon(String filename) {
         if (!FileUtils.isValidExtFilename(filename)
                 || !filename.contains(ActivityRecord.ACTIVITY_ICON_SUFFIX)) {
@@ -8032,7 +8062,7 @@
      * @return Returns true if the given task was found and removed.
      */
     private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
-        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
         if (tr != null) {
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, killProcess);
@@ -8285,7 +8315,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
                 return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4d7305d..c073df6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -152,25 +152,25 @@
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
      */
-    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<TaskRecord>();
+    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
 
     /**
      * Used for validating app tokens with window manager.
      */
-    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<TaskGroup>();
+    final ArrayList<TaskGroup> mValidateAppTokens = new ArrayList<>();
 
     /**
      * List of running activities, sorted by recent usage.
      * The first entry in the list is the least recently used.
      * It contains HistoryRecord objects.
      */
-    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mLRUActivities = new ArrayList<>();
 
     /**
      * Animations that for the current transition have requested not to
      * be considered for the transition animation.
      */
-    final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<ActivityRecord>();
+    final ArrayList<ActivityRecord> mNoAnimActivities = new ArrayList<>();
 
     /**
      * When we are in the process of pausing an activity, before starting the
@@ -346,6 +346,10 @@
         return count;
     }
 
+    int numTasks() {
+        return mTaskHistory.size();
+    }
+
     ActivityStack(ActivityStackSupervisor.ActivityContainer activityContainer,
             RecentTasks recentTasks) {
         mActivityContainer = activityContainer;
@@ -492,11 +496,19 @@
 
     final void moveToFront(String reason) {
         if (isAttached()) {
-            if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(isHomeStack(), reason);
+            final boolean homeStack = isHomeStack()
+                    || (mActivityContainer.mParentActivity != null
+                        && mActivityContainer.mParentActivity.isHomeActivity());
+
+            if (!homeStack) {
+                // Need to move this stack to the front before calling
+                // {@link ActivityStackSupervisor#moveHomeStack} below.
+                mStacks.remove(this);
+                mStacks.add(this);
             }
-            mStacks.remove(this);
-            mStacks.add(this);
+            if (isOnHomeDisplay()) {
+                mStackSupervisor.moveHomeStack(homeStack, reason);
+            }
             final TaskRecord task = topTask();
             if (task != null) {
                 mWindowManager.moveTaskToTop(task.taskId);
@@ -1154,6 +1166,23 @@
         return null;
     }
 
+    private ActivityStack getNextVisibleStackLocked() {
+        ArrayList<ActivityStack> stacks = mStacks;
+        final ActivityRecord parent = mActivityContainer.mParentActivity;
+        if (parent != null) {
+            stacks = parent.task.stack.mStacks;
+        }
+        if (stacks != null) {
+            for (int i = stacks.size() - 1; i >= 0; --i) {
+                ActivityStack stack = stacks.get(i);
+                if (stack != this && stack.isStackVisibleLocked()) {
+                    return stack;
+                }
+            }
+        }
+        return null;
+    }
+
     // 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 isStackVisibleLocked() {
@@ -1482,7 +1511,7 @@
         return result;
     }
 
-    final boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
+    private boolean resumeTopActivityInnerLocked(ActivityRecord prev, Bundle options) {
         if (ActivityManagerService.DEBUG_LOCKSCREEN) mService.logLockScreen("");
 
         if (!mService.mBooting && !mService.mBooted) {
@@ -1510,8 +1539,17 @@
 
         final TaskRecord prevTask = prev != null ? prev.task : null;
         if (next == null) {
-            // There are no more activities!  Let's just start up the
-            // Launcher...
+            // There are no more activities!
+            final String reason = "noMoreActivities";
+            if (!mFullscreen) {
+                // Try to move focus to the next visible stack with a running activity if this
+                // stack is not covering the entire screen.
+                final ActivityStack stack = getNextVisibleStackLocked();
+                if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
+                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
+                }
+            }
+            // Let's just start up the Launcher...
             ActivityOptions.abort(options);
             if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: No more activities go home");
             if (DEBUG_STACK) mStackSupervisor.validateTopActivitiesLocked();
@@ -1519,7 +1557,7 @@
             final int returnTaskType = prevTask == null || !prevTask.isOverHomeStack() ?
                     HOME_ACTIVITY_TYPE : prevTask.getTaskToReturnTo();
             return isOnHomeDisplay() &&
-                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, "noMoreActivities");
+                    mStackSupervisor.resumeHomeStackTask(returnTaskType, prev, reason);
         }
 
         next.delayedResume = false;
@@ -2516,20 +2554,44 @@
     private void adjustFocusedActivityLocked(ActivityRecord r, String reason) {
         if (mStackSupervisor.isFrontStack(this) && mService.mFocusedActivity == r) {
             ActivityRecord next = topRunningActivityLocked(null);
+            final String myReason = reason + " adjustFocus";
             if (next != r) {
                 final TaskRecord task = r.task;
                 if (r.frontOfTask && task == topTask() && task.isOverHomeStack()) {
-                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(),
-                            reason + " adjustFocus");
+                    // For non-fullscreen stack, we want to move the focus to the next visible
+                    // stack to prevent the home screen from moving to the top and obscuring
+                    // other visible stacks.
+                    if (!mFullscreen
+                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                        return;
+                    }
+                    // Move the home stack to the top if this stack is fullscreen or there is no
+                    // other visible stack.
+                    mStackSupervisor.moveHomeStackTaskToTop(task.getTaskToReturnTo(), myReason);
                 }
             }
-            ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
+
+            final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
             if (top != null) {
-                mService.setFocusedActivityLocked(top, reason + " adjustTopFocus");
+                mService.setFocusedActivityLocked(top, myReason);
             }
         }
     }
 
+    private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
+        final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
+        final String myReason = reason + " adjustFocusToNextVisibleStack";
+        if (stack == null) {
+            return false;
+        }
+        final ActivityRecord top = stack.topRunningActivityLocked(null);
+        if (top == null) {
+            return false;
+        }
+        mService.setFocusedActivityLocked(top, myReason);
+        return true;
+    }
+
     final void stopActivityLocked(ActivityRecord r) {
         if (DEBUG_SWITCH) Slog.d(TAG, "Stopping: " + r);
         if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
@@ -2999,6 +3061,8 @@
      * representation) and cleaning things up as a result of its hosting
      * processing going away, in which case there is no remaining client-side
      * state to destroy so only the cleanup here is needed.
+     *
+     * Note: Call before #removeActivityFromHistoryLocked.
      */
     final void cleanUpActivityLocked(ActivityRecord r, boolean cleanServices,
             boolean setState) {
@@ -3410,7 +3474,7 @@
                 if (DEBUG_CLEANUP) Slog.v(
                     TAG, "Record #" + i + " " + r + ": app=" + r.app);
                 if (r.app == app) {
-                    boolean remove;
+                    final boolean remove;
                     if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
                         // Don't currently have state for the activity, or
                         // it is finishing -- always remove it.
@@ -3444,8 +3508,6 @@
                                 mService.updateUsageStats(r, false);
                             }
                         }
-                        removeActivityFromHistoryLocked(r, "appDied");
-
                     } else {
                         // We have the current state for this activity, so
                         // it can be restarted later when needed.
@@ -3464,8 +3526,10 @@
                             r.icicle = null;
                         }
                     }
-
                     cleanUpActivityLocked(r, true, true);
+                    if (remove) {
+                        removeActivityFromHistoryLocked(r, "appDied");
+                    }
                 }
             }
         }
@@ -3599,8 +3663,7 @@
             }
         }
 
-        if (DEBUG_TRANSITION) Slog.v(TAG,
-                "Prepare to back transition: task=" + taskId);
+        if (DEBUG_TRANSITION) Slog.v(TAG, "Prepare to back transition: task=" + taskId);
 
         boolean prevIsHome = false;
         if (tr.isOverHomeStack()) {
@@ -4126,8 +4189,14 @@
     }
 
     void removeTask(TaskRecord task, String reason) {
+        removeTask(task, reason, true);
+    }
+
+    void removeTask(TaskRecord task, String reason, boolean removeFromWindowManager) {
         mStackSupervisor.endLockTaskModeIfTaskEnding(task);
-        mWindowManager.removeTask(task.taskId);
+        if (removeFromWindowManager) {
+            mWindowManager.removeTask(task.taskId);
+        }
         final ActivityRecord r = mResumedActivity;
         if (r != null && r.task == task) {
             mResumedActivity = null;
@@ -4161,16 +4230,24 @@
         }
 
         if (mTaskHistory.isEmpty()) {
-            if (DEBUG_STACK) Slog.i(TAG, "removeTask: moving to back stack=" + this);
+            if (DEBUG_STACK) Slog.i(TAG, "removeTask: removing stack=" + this);
+            final boolean notHomeStack = !isHomeStack();
             if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(!isHomeStack(), reason + " leftTaskHistoryEmpty");
+                String myReason = reason + " leftTaskHistoryEmpty";
+                if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                    mStackSupervisor.moveHomeStack(notHomeStack, myReason);
+                }
             }
             if (mStacks != null) {
                 mStacks.remove(this);
                 mStacks.add(0, this);
             }
-            mActivityContainer.onTaskListEmptyLocked();
+            if (notHomeStack) {
+                mActivityContainer.onTaskListEmptyLocked();
+            }
         }
+
+        task.stack = null;
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1aa2a10..f6ef295 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -386,8 +386,8 @@
         return mLastFocusedStack;
     }
 
-    // TODO: Split into two methods isFrontStack for any visible stack and isFrontmostStack for the
-    // top of all visible stacks.
+    /** Top of all visible stacks. Use {@link ActivityStack#isStackVisibleLocked} to determine if a
+     * specific stack is visible or not. */
     boolean isFrontStack(ActivityStack stack) {
         final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
         if (parent != null) {
@@ -462,6 +462,16 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
+        return anyTaskForIdLocked(id, true);
+    }
+
+    /**
+     * Returns a {@link TaskRecord} for the input id if available. Null otherwise.
+     * @param id Id of the task we would like returned.
+     * @param restoreFromRecents If the id was not in the active list, but was found in recents,
+     *                           restore the task from recents to the active list.
+     */
+    TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -482,6 +492,10 @@
             return null;
         }
 
+        if (!restoreFromRecents) {
+            return task;
+        }
+
         if (!restoreRecentTaskLocked(task)) {
             if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -516,12 +530,12 @@
             if (mCurTaskId <= 0) {
                 mCurTaskId = 1;
             }
-        } while (anyTaskForIdLocked(mCurTaskId) != null);
+        } while (anyTaskForIdLocked(mCurTaskId, false) != null);
         return mCurTaskId;
     }
 
     ActivityRecord resumedAppLocked() {
-        ActivityStack stack = getFocusedStack();
+        ActivityStack stack = mFocusedStack;
         if (stack == null) {
             return null;
         }
@@ -725,7 +739,7 @@
     }
 
     ActivityRecord topRunningActivityLocked() {
-        final ActivityStack focusedStack = getFocusedStack();
+        final ActivityStack focusedStack = mFocusedStack;
         ActivityRecord r = focusedStack.topRunningActivityLocked(null);
         if (r != null) {
             return r;
@@ -871,7 +885,7 @@
 
             final ActivityStack stack;
             if (container == null || container.mStack.isOnHomeDisplay()) {
-                stack = getFocusedStack();
+                stack = mFocusedStack;
             } else {
                 stack = container.mStack;
             }
@@ -1488,7 +1502,7 @@
             outActivity[0] = r;
         }
 
-        final ActivityStack stack = getFocusedStack();
+        final ActivityStack stack = mFocusedStack;
         if (voiceSession == null && (stack.mResumedActivity == null
                 || stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
             if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
@@ -1527,25 +1541,27 @@
         return err;
     }
 
-    ActivityStack adjustStackFocus(ActivityRecord r, boolean newTask) {
+    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
         final TaskRecord task = r.task;
 
         // On leanback only devices we should keep all activities in the same stack.
         if (!mLeanbackOnlyDevice &&
                 (r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
+
+            ActivityStack stack;
+
             if (task != null) {
-                final ActivityStack taskStack = task.stack;
-                if (taskStack.isOnHomeDisplay()) {
-                    if (mFocusedStack != taskStack) {
-                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: Setting " +
+                stack = task.stack;
+                if (stack.isOnHomeDisplay()) {
+                    if (mFocusedStack != stack) {
+                        if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: Setting " +
                                 "focused stack to r=" + r + " task=" + task);
-                        mFocusedStack = taskStack;
                     } else {
                         if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Focused stack already=" + mFocusedStack);
+                            "computeStackFocus: Focused stack already=" + mFocusedStack);
                     }
                 }
-                return taskStack;
+                return stack;
             }
 
             final ActivityContainer container = r.mInitialActivityContainer;
@@ -1558,43 +1574,41 @@
             if (mFocusedStack != mHomeStack && (!newTask ||
                     mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                        "adjustStackFocus: Have a focused stack=" + mFocusedStack);
+                        "computeStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
             }
 
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = homeDisplayStacks.get(stackNdx);
+                stack = homeDisplayStacks.get(stackNdx);
                 if (!stack.isHomeStack()) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG,
-                            "adjustStackFocus: Setting focused stack=" + stack);
-                    mFocusedStack = stack;
-                    return mFocusedStack;
+                            "computeStackFocus: Setting focused stack=" + stack);
+                    return stack;
                 }
             }
 
             // Need to create an app stack for this user.
-            mFocusedStack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
-            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "adjustStackFocus: New stack r=" + r +
-                    " stackId=" + mFocusedStack.mStackId);
-            return mFocusedStack;
+            stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
+            if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG, "computeStackFocus: New stack r=" + r +
+                    " stackId=" + stack.mStackId);
+            return stack;
         }
         return mHomeStack;
     }
 
-    void setFocusedStack(ActivityRecord r, String reason) {
-        if (r != null) {
-            final TaskRecord task = r.task;
-            boolean isHomeActivity = !r.isApplicationActivity();
-            if (!isHomeActivity && task != null) {
-                isHomeActivity = !task.isApplicationTask();
-            }
-            if (!isHomeActivity && task != null) {
-                final ActivityRecord parent = task.stack.mActivityContainer.mParentActivity;
-                isHomeActivity = parent != null && parent.isHomeActivity();
-            }
-            moveHomeStack(isHomeActivity, reason);
+    boolean setFocusedStack(ActivityRecord r, String reason) {
+        if (r == null) {
+            // Not sure what you are trying to do, but it is not going to work...
+            return false;
         }
+        final TaskRecord task = r.task;
+        if (task == null || task.stack == null) {
+            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            return false;
+        }
+        task.stack.moveToFront(reason);
+        return true;
     }
 
     final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
@@ -1692,7 +1706,7 @@
         if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
             ActivityRecord checkedCaller = sourceRecord;
             if (checkedCaller == null) {
-                checkedCaller = getFocusedStack().topRunningNonDelayedActivityLocked(notTop);
+                checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
             }
             if (!checkedCaller.realActivity.equals(r.realActivity)) {
                 // Caller is not the same as launcher, so always needed.
@@ -2016,7 +2030,7 @@
             // If the activity being launched is the same as the one currently
             // at the top, then we need to check if it should only be launched
             // once.
-            ActivityStack topStack = getFocusedStack();
+            ActivityStack topStack = mFocusedStack;
             ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
             if (top != null && r.resultTo == null) {
                 if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
@@ -2068,10 +2082,9 @@
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
             newTask = true;
-            targetStack = adjustStackFocus(r, newTask);
-            if (!launchTaskBehind) {
-                targetStack.moveToFront("startingNewTask");
-            }
+            targetStack = computeStackFocus(r, newTask);
+            targetStack.moveToFront("startingNewTask");
+
             if (reuseTask == null) {
                 r.setTask(targetStack.createTaskRecord(getNextTaskId(),
                         newTaskInfo != null ? newTaskInfo : r.info,
@@ -2192,7 +2205,7 @@
             // This not being started from an existing activity, and not part
             // of a new task...  just put it in the top task, though these days
             // this case should never happen.
-            targetStack = adjustStackFocus(r, newTask);
+            targetStack = computeStackFocus(r, newTask);
             targetStack.moveToFront("addingToTopTask");
             ActivityRecord prev = targetStack.topActivity();
             r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(getNextTaskId(),
@@ -2468,13 +2481,14 @@
     boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
             Bundle targetOptions) {
         if (targetStack == null) {
-            targetStack = getFocusedStack();
+            targetStack = mFocusedStack;
         }
         // Do targetStack first.
         boolean result = false;
         if (isFrontStack(targetStack)) {
             result = targetStack.resumeTopActivityLocked(target, targetOptions);
         }
+
         for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
             final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
             for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
@@ -2626,6 +2640,48 @@
         }
     }
 
+    /** Makes sure the input task is in a stack with the specified bounds by either resizing the
+     * current task stack if it only has one entry, moving the task to a stack that matches the
+     * bounds, or creating a new stack with the required bounds. Also, makes the task resizeable.*/
+    void resizeTaskLocked(TaskRecord task, Rect bounds) {
+        task.mResizeable = true;
+        final ActivityStack currentStack = task.stack;
+        if (currentStack.isHomeStack()) {
+            // Can't move task off the home stack. Sorry!
+            return;
+        }
+
+        final int matchingStackId = mWindowManager.getStackIdWithBounds(bounds);
+        if (matchingStackId != -1) {
+            // There is already a stack with the right bounds!
+            if (currentStack != null && currentStack.mStackId == matchingStackId) {
+                // Nothing to do here. Already in the right stack...
+                return;
+            }
+            // Move task to stack with matching bounds.
+            moveTaskToStackLocked(task.taskId, matchingStackId, true);
+            return;
+        }
+
+        if (currentStack != null && currentStack.numTasks() == 1) {
+            // Just resize the current stack since this is the task in it.
+            resizeStackLocked(currentStack.mStackId, bounds);
+            return;
+        }
+
+        // Create new stack and move the task to it.
+        final int displayId = (currentStack != null && currentStack.mDisplayId != -1)
+                ? currentStack.mDisplayId : Display.DEFAULT_DISPLAY;
+        ActivityStack newStack = createStackOnDisplay(getNextStackId(), displayId);
+
+        if (newStack == null) {
+            Slog.e(TAG, "resizeTaskLocked: Can't create stack for task=" + task);
+            return;
+        }
+        moveTaskToStackLocked(task.taskId, newStack.mStackId, true);
+        resizeStackLocked(newStack.mStackId, bounds);
+    }
+
     ActivityStack createStackOnDisplay(int stackId, int displayId) {
         ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
         if (activityDisplay == null) {
@@ -2661,7 +2717,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack()) {
+                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
                     stack = tmpStack;
                     break;
                 }
@@ -2704,6 +2760,7 @@
     void moveTaskToStackLocked(int taskId, int stackId, boolean toTop) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
+            Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
             return;
         }
         final ActivityStack stack = getStack(stackId);
@@ -2711,9 +2768,11 @@
             Slog.w(TAG, "moveTaskToStack: no stack for id=" + stackId);
             return;
         }
-        task.stack.removeTask(task, "moveTaskToStack");
+        mWindowManager.moveTaskToStack(taskId, stackId, toTop);
+        if (task.stack != null) {
+            task.stack.removeTask(task, "moveTaskToStack", false);
+        }
         stack.addTask(task, toTop, true);
-        mWindowManager.addTask(taskId, stackId, toTop);
         resumeTopActivitiesLocked();
     }
 
@@ -3054,7 +3113,7 @@
     }
 
     boolean switchUserLocked(int userId, UserStartedState uss) {
-        mUserStackInFront.put(mCurrentUser, getFocusedStack().getStackId());
+        mUserStackInFront.put(mCurrentUser, mFocusedStack.getStackId());
         final int restoreStackId = mUserStackInFront.get(userId, HOME_STACK_ID);
         mCurrentUser = userId;
 
@@ -3178,7 +3237,7 @@
     }
 
     ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
-        return getFocusedStack().getDumpActivitiesLocked(name);
+        return mFocusedStack.getDumpActivitiesLocked(name);
     }
 
     static boolean printThisActivity(PrintWriter pw, ActivityRecord activity, String dumpPackage,
@@ -3928,6 +3987,10 @@
         }
 
         void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            detachLocked();
+            deleteActivityContainer(this);
+            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
         @Override
@@ -4016,13 +4079,6 @@
             return false;
         }
 
-        void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-            detachLocked();
-            deleteActivityContainer(this);
-            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
-        }
-
         private void setSurfaceIfReadyLocked() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 7ab3794..6a29d85 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -187,10 +187,12 @@
 
     public void enqueueParallelBroadcastLocked(BroadcastRecord r) {
         mParallelBroadcasts.add(r);
+        r.enqueueClockTime = System.currentTimeMillis();
     }
 
     public void enqueueOrderedBroadcastLocked(BroadcastRecord r) {
         mOrderedBroadcasts.add(r);
+        r.enqueueClockTime = System.currentTimeMillis();
     }
 
     public final boolean replaceParallelBroadcastLocked(BroadcastRecord r) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index b2cfd7a..9a4d7a0 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -52,6 +52,7 @@
     final int appOp;        // an app op that is associated with this broadcast
     final List receivers;   // contains BroadcastFilter and ResolveInfo
     IIntentReceiver resultTo; // who receives final result if non-null
+    long enqueueClockTime;  // the clock time the broadcast was enqueued
     long dispatchTime;      // when dispatch started on this set of receivers
     long dispatchClockTime; // the clock time the dispatch started
     long receiverTime;      // when current receiver started for timeouts.
@@ -102,7 +103,9 @@
             pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission);
                     pw.print("  appOp="); pw.println(appOp);
         }
-        pw.print(prefix); pw.print("dispatchClockTime=");
+        pw.print(prefix); pw.print("enqueueClockTime=");
+                pw.print(new Date(enqueueClockTime));
+                pw.print(" dispatchClockTime=");
                 pw.println(new Date(dispatchClockTime));
         pw.print(prefix); pw.print("dispatchTime=");
                 TimeUtils.formatDuration(dispatchTime, now, pw);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4ea62ec..afe7d7a 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -581,8 +581,7 @@
 
         AudioSystem.setErrorCallback(mAudioSystemCallback);
 
-        boolean cameraSoundForced = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_camera_sound_forced);
+        boolean cameraSoundForced = readCameraSoundForced();
         mCameraSoundForced = new Boolean(cameraSoundForced);
         sendMsg(mAudioHandler,
                 MSG_SET_FORCE_USE,
@@ -1107,11 +1106,6 @@
                 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) &&
@@ -1188,8 +1182,7 @@
             synchronized (mHdmiTvClient) {
                 final long token = Binder.clearCallingIdentity();
                 try {
-                    mHdmiTvClient.setSystemAudioVolume(
-                            (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
+                    mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
                 } finally {
                     Binder.restoreCallingIdentity(token);
                 }
@@ -1459,16 +1452,6 @@
             flags = updateFlagsForSystemAudio(flags);
         }
         mVolumeController.postVolumeChanged(streamType, flags);
-
-        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
-            oldIndex = (oldIndex + 5) / 10;
-            index = (index + 5) / 10;
-            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
-            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
-            sendBroadcastToAll(intent);
-        }
     }
 
     // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
@@ -3506,6 +3489,7 @@
         private int mIndexMax;
         private final ConcurrentHashMap<Integer, Integer> mIndex =
                                             new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
+        private final Intent mVolumeChanged;
 
         private VolumeStreamState(String settingName, int streamType) {
 
@@ -3517,6 +3501,8 @@
             mIndexMax *= 10;
 
             readSettings();
+            mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
+            mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
         }
 
         public String getSettingNameForDevice(int device) {
@@ -3631,8 +3617,10 @@
         }
 
         public boolean setIndex(int index, int device) {
+            boolean changed = false;
+            int oldIndex;
             synchronized (VolumeStreamState.class) {
-                int oldIndex = getIndex(device);
+                oldIndex = getIndex(device);
                 index = getValidIndex(index);
                 synchronized (mCameraSoundForced) {
                     if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
@@ -3641,7 +3629,8 @@
                 }
                 mIndex.put(device, index);
 
-                if (oldIndex != index) {
+                changed = oldIndex != index;
+                if (changed) {
                     // Apply change to all streams using this one as alias
                     // if changing volume of current device, also change volume of current
                     // device on aliased stream
@@ -3659,11 +3648,16 @@
                             }
                         }
                     }
-                    return true;
-                } else {
-                    return false;
                 }
             }
+            if (changed) {
+                oldIndex = (oldIndex + 5) / 10;
+                index = (index + 5) / 10;
+                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
+                sendBroadcastToAll(mVolumeChanged);
+            }
+            return changed;
         }
 
         public int getIndex(int device) {
@@ -3720,9 +3714,12 @@
         }
 
         public void mute(boolean state) {
+            boolean changed = false;
             synchronized (VolumeStreamState.class) {
                 if (state != mIsMuted) {
+                    changed = true;
                     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.
@@ -3734,6 +3731,13 @@
                             this, 0);
                 }
             }
+            if (changed) {
+                // Stream mute changed, fire the intent.
+                Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+                intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+                intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
+                sendBroadcastToAll(intent);
+            }
         }
 
         public int getStreamType() {
@@ -5071,6 +5075,12 @@
         return mMediaFocusControl.getCurrentAudioFocus();
     }
 
+    private boolean readCameraSoundForced() {
+        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
+                mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_camera_sound_forced);
+    }
+
     //==========================================================================================
     // Device orientation
     //==========================================================================================
@@ -5101,8 +5111,7 @@
                     null,
                     0);
 
-            boolean cameraSoundForced = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_camera_sound_forced);
+            boolean cameraSoundForced = readCameraSoundForced();
             synchronized (mSettingsLock) {
                 boolean cameraSoundForcedChanged = false;
                 synchronized (mCameraSoundForced) {
@@ -5517,6 +5526,7 @@
         pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
         pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
         pw.print("  mMcc="); pw.println(mMcc);
+        pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
         pw.print("  mHasVibrator="); pw.println(mHasVibrator);
         pw.print("  mControllerService="); pw.println(mControllerService);
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 4f458e6..cfc9132 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -881,7 +881,7 @@
         HdmiLogger.debug("Set Arc Status[old:%b new:%b]", mArcEstablished, enabled);
         boolean oldStatus = mArcEstablished;
         // 1. Enable/disable ARC circuit.
-        mService.setAudioReturnChannel(getAvrDeviceInfo().getPortId(), enabled);
+        setAudioReturnChannel(enabled);
         // 2. Notify arc status to audio service.
         notifyArcStatusToAudioService(enabled);
         // 3. Update arc status;
@@ -889,6 +889,18 @@
         return oldStatus;
     }
 
+    /**
+     * Switch hardware ARC circuit in the system.
+     */
+    @ServiceThreadOnly
+    void setAudioReturnChannel(boolean enabled) {
+        assertRunOnServiceThread();
+        HdmiDeviceInfo avr = getAvrDeviceInfo();
+        if (avr != null) {
+            mService.setAudioReturnChannel(avr.getPortId(), enabled);
+        }
+    }
+
     @ServiceThreadOnly
     private void updateArcFeatureStatus(int portId, boolean isConnected) {
         assertRunOnServiceThread();
diff --git a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
index 1bbd038..f7555e9 100644
--- a/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
+++ b/services/core/java/com/android/server/hdmi/HotplugDetectionAction.java
@@ -262,6 +262,7 @@
         // Turn off system audio mode and update settings.
         tv().setSystemAudioMode(false, true);
         if (tv().isArcEstabilished()) {
+            tv().setAudioReturnChannel(false);
             addAndStartAction(new RequestArcTerminationAction(localDevice(), address));
         }
     }
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 06c154e..a5efc83 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -338,6 +338,7 @@
      */
     private void enforceMediaPermissions(ComponentName compName, int pid, int uid,
             int resolvedUserId) {
+        if (isCurrentVolumeController(uid)) return;
         if (getContext()
                 .checkPermission(android.Manifest.permission.MEDIA_CONTENT_CONTROL, pid, uid)
                     != PackageManager.PERMISSION_GRANTED
@@ -347,13 +348,18 @@
         }
     }
 
-    private void enforceSystemUiPermission(String action, int pid, int uid) {
+    private boolean isCurrentVolumeController(int uid) {
         if (mAudioManagerInternal != null) {
             final int vcuid = mAudioManagerInternal.getVolumeControllerUid();
             if (vcuid > 0 && uid == vcuid) {
-                return;
+                return true;
             }
         }
+        return false;
+    }
+
+    private void enforceSystemUiPermission(String action, int pid, int uid) {
+        if (isCurrentVolumeController(uid)) return;
         if (getContext().checkPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
                 pid, uid) != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("Only system ui may " + action);
diff --git a/services/core/java/com/android/server/policy/BarController.java b/services/core/java/com/android/server/policy/BarController.java
index bca2c16..e972ec7 100644
--- a/services/core/java/com/android/server/policy/BarController.java
+++ b/services/core/java/com/android/server/policy/BarController.java
@@ -43,15 +43,15 @@
 
     private static final int TRANSLUCENT_ANIMATION_DELAY_MS = 1000;
 
-    private final String mTag;
+    protected final String mTag;
     private final int mTransientFlag;
     private final int mUnhideFlag;
     private final int mTranslucentFlag;
     private final int mStatusBarManagerId;
     private final int mTranslucentWmFlag;
-    private final Handler mHandler;
+    protected final Handler mHandler;
     private final Object mServiceAquireLock = new Object();
-    private IStatusBarService mStatusBarService;
+    protected IStatusBarService mStatusBarService;
 
     private WindowState mWin;
     private int mState = StatusBarManager.WINDOW_STATE_SHOWING;
@@ -254,7 +254,7 @@
         }
     }
 
-    private IStatusBarService getStatusBarService() {
+    protected IStatusBarService getStatusBarService() {
         synchronized (mServiceAquireLock) {
             if (mStatusBarService == null) {
                 mStatusBarService = IStatusBarService.Stub.asInterface(
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index b90d263..f691b4e 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -74,6 +74,7 @@
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -103,6 +104,8 @@
 import android.view.animation.Animation;
 import android.view.animation.AnimationSet;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.view.animation.TranslateAnimation;
 
 import com.android.internal.R;
 import com.android.internal.statusbar.IStatusBarService;
@@ -724,12 +727,7 @@
     }
     MyOrientationListener mOrientationListener;
 
-    private final BarController mStatusBarController = new BarController("StatusBar",
-            View.STATUS_BAR_TRANSIENT,
-            View.STATUS_BAR_UNHIDE,
-            View.STATUS_BAR_TRANSLUCENT,
-            StatusBarManager.WINDOW_STATUS_BAR,
-            WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+    private final StatusBarController mStatusBarController = new StatusBarController();
 
     private final BarController mNavigationBarController = new BarController("NavigationBar",
             View.NAVIGATION_BAR_TRANSIENT,
@@ -1359,6 +1357,9 @@
         if (!mPowerManager.isInteractive()) {
             goingToSleep(WindowManagerPolicy.OFF_BECAUSE_OF_USER);
         }
+
+        mWindowManagerInternal.registerAppTransitionListener(
+                mStatusBarController.getAppTransitionListener());
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
new file mode 100644
index 0000000..4d4ab44
--- /dev/null
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -0,0 +1,187 @@
+/*
+ * 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.server.policy;
+
+import android.app.StatusBarManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerInternal;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.Interpolator;
+import android.view.animation.TranslateAnimation;
+
+import com.android.internal.statusbar.IStatusBarService;
+
+import static android.view.WindowManagerInternal.*;
+
+/**
+ * Implements status bar specific behavior.
+ */
+public class StatusBarController extends BarController {
+
+    private static final long TRANSITION_DURATION = 120L;
+
+    private final AppTransitionListener mAppTransitionListener
+            = new AppTransitionListener() {
+
+        @Override
+        public void onAppTransitionPendingLocked() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.appTransitionPending();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is pending", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onAppTransitionStartingLocked(IBinder openToken, IBinder closeToken,
+                final Animation openAnimation, final Animation closeAnimation) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            long startTime = calculateStatusBarTransitionStartTime(openAnimation,
+                                    closeAnimation);
+                            statusbar.appTransitionStarting(startTime, TRANSITION_DURATION);
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is starting", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+
+        @Override
+        public void onAppTransitionCancelledLocked() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        IStatusBarService statusbar = getStatusBarService();
+                        if (statusbar != null) {
+                            statusbar.appTransitionCancelled();
+                        }
+                    } catch (RemoteException e) {
+                        Slog.e(mTag, "RemoteException when app transition is cancelled", e);
+                        // re-acquire status bar service next time it is needed.
+                        mStatusBarService = null;
+                    }
+                }
+            });
+        }
+    };
+
+    public StatusBarController() {
+        super("StatusBar",
+                View.STATUS_BAR_TRANSIENT,
+                View.STATUS_BAR_UNHIDE,
+                View.STATUS_BAR_TRANSLUCENT,
+                StatusBarManager.WINDOW_STATUS_BAR,
+                WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+    }
+
+    public AppTransitionListener getAppTransitionListener() {
+        return mAppTransitionListener;
+    }
+
+    /**
+     * For a given app transition with {@code openAnimation} and {@code closeAnimation}, this
+     * calculates the timings for the corresponding status bar transition.
+     *
+     * @return the desired start time of the status bar transition, in uptime millis
+     */
+    private long calculateStatusBarTransitionStartTime(Animation openAnimation,
+            Animation closeAnimation) {
+        if (openAnimation != null && closeAnimation != null) {
+            TranslateAnimation openTranslateAnimation = findTranslateAnimation(openAnimation);
+            TranslateAnimation closeTranslateAnimation = findTranslateAnimation(closeAnimation);
+            if (openTranslateAnimation != null) {
+
+                // Some interpolators are extremely quickly mostly finished, but not completely. For
+                // our purposes, we need to find the fraction for which ther interpolator is mostly
+                // there, and use that value for the calculation.
+                float t = findAlmostThereFraction(openTranslateAnimation.getInterpolator());
+                return SystemClock.uptimeMillis()
+                        + openTranslateAnimation.getStartOffset()
+                        + (long)(openTranslateAnimation.getDuration()*t) - TRANSITION_DURATION;
+            } else if (closeTranslateAnimation != null) {
+                return SystemClock.uptimeMillis();
+            } else {
+                return SystemClock.uptimeMillis();
+            }
+        } else {
+            return SystemClock.uptimeMillis();
+        }
+    }
+
+    /**
+     * Tries to find a {@link TranslateAnimation} inside the {@code animation}.
+     *
+     * @return the found animation, {@code null} otherwise
+     */
+    private TranslateAnimation findTranslateAnimation(Animation animation) {
+        if (animation instanceof TranslateAnimation) {
+            return (TranslateAnimation) animation;
+        } else if (animation instanceof AnimationSet) {
+            AnimationSet set = (AnimationSet) animation;
+            for (int i = 0; i < set.getAnimations().size(); i++) {
+                Animation a = set.getAnimations().get(i);
+                if (a instanceof TranslateAnimation) {
+                    return (TranslateAnimation) a;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Binary searches for a {@code t} such that there exists a {@code -0.01 < eps < 0.01} for which
+     * {@code interpolator(t + eps) > 0.99}.
+     */
+    private float findAlmostThereFraction(Interpolator interpolator) {
+        float val = 0.5f;
+        float adj = 0.25f;
+        while (adj >= 0.01f) {
+            if (interpolator.getInterpolation(val) < 0.99f) {
+                val += adj;
+            } else {
+                val -= adj;
+            }
+            adj /= 2;
+        }
+        return val;
+    }
+}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 9786b42..66c2f5f 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -128,6 +128,7 @@
     private static final int WAKE_LOCK_PROXIMITY_SCREEN_OFF = 1 << 4;
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
+    private static final int WAKE_LOCK_DRAW = 1 << 7;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -1398,12 +1399,15 @@
                     case PowerManager.DOZE_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DOZE;
                         break;
+                    case PowerManager.DRAW_WAKE_LOCK:
+                        mWakeLockSummary |= WAKE_LOCK_DRAW;
+                        break;
                 }
             }
 
             // Cancel wake locks that make no sense based on the current state.
             if (mWakefulness != WAKEFULNESS_DOZING) {
-                mWakeLockSummary &= ~WAKE_LOCK_DOZE;
+                mWakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
             }
             if (mWakefulness == WAKEFULNESS_ASLEEP
                     || (mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
@@ -1422,6 +1426,9 @@
                     mWakeLockSummary |= WAKE_LOCK_CPU;
                 }
             }
+            if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+                mWakeLockSummary |= WAKE_LOCK_CPU;
+            }
 
             if (DEBUG_SPEW) {
                 Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
@@ -1845,6 +1852,10 @@
 
             if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
                 mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
+                if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
+                        && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+                    mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+                }
                 mDisplayPowerRequest.dozeScreenBrightness =
                         mDozeScreenBrightnessOverrideFromDreamManager;
             } else {
@@ -2712,6 +2723,8 @@
                     return "PROXIMITY_SCREEN_OFF_WAKE_LOCK";
                 case PowerManager.DOZE_WAKE_LOCK:
                     return "DOZE_WAKE_LOCK                ";
+                case PowerManager.DRAW_WAKE_LOCK:
+                    return "DRAW_WAKE_LOCK                ";
                 default:
                     return "???                           ";
             }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index cf2ed07..f6df757 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -454,6 +454,35 @@
         }
     }
 
+    @Override
+    public void appTransitionPending() {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionPending();
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionCancelled();
+            } catch (RemoteException ex) {}
+        }
+    }
+
+    @Override
+    public void appTransitionStarting(long statusBarAnimationsStartTime,
+            long statusBarAnimationsDuration) {
+        if (mBar != null) {
+            try {
+                mBar.appTransitionStarting(
+                        statusBarAnimationsStartTime, statusBarAnimationsDuration);
+            } catch (RemoteException ex) {}
+        }
+    }
+
     private void enforceStatusBar() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR,
                 "StatusBarManagerService");
@@ -625,7 +654,6 @@
         }
     }
 
-
     // ================================================================================
     // Can be called from any thread
     // ================================================================================
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 50b2262..c5f4161 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -699,15 +699,14 @@
 
         private void findAudioSinkFromAudioPolicy(List<AudioDevicePort> sinks) {
             sinks.clear();
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return;
             }
             int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if ((devicePort.type() & sinkDevice) != 0) {
-                    sinks.add(devicePort);
+            for (AudioDevicePort port : devicePorts) {
+                if ((port.type() & sinkDevice) != 0) {
+                    sinks.add(port);
                 }
             }
         }
@@ -716,14 +715,13 @@
             if (type == AudioManager.DEVICE_NONE) {
                 return null;
             }
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return null;
             }
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if (devicePort.type() == type && devicePort.address().equals(address)) {
-                    return devicePort;
+            for (AudioDevicePort port : devicePorts) {
+                if (port.type() == type && port.address().equals(address)) {
+                    return port;
                 }
             }
             return null;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 2afeaab..ef70895 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -17,16 +17,13 @@
 package com.android.server.wm;
 
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.os.Debug;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.IRemoteCallback;
-import android.os.UserHandle;
-import android.util.Log;
 import android.util.Slog;
 import android.view.WindowManager;
 import android.view.animation.AlphaAnimation;
@@ -47,7 +44,9 @@
 import com.android.server.wm.WindowManagerService.H;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
 
+import static android.view.WindowManagerInternal.AppTransitionListener;
 import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
 import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
@@ -185,6 +184,8 @@
 
     private int mCurrentUserId = 0;
 
+    private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
+
     AppTransition(Context context, Handler h) {
         mContext = context;
         mH = h;
@@ -291,12 +292,18 @@
     void prepare() {
         if (!isRunning()) {
             mAppTransitionState = APP_STATE_IDLE;
+            notifyAppTransitionPendingLocked();
         }
     }
 
-    void goodToGo() {
+    void goodToGo(AppWindowAnimator openingAppAnimator, AppWindowAnimator closingAppAnimator) {
         mNextAppTransition = TRANSIT_UNSET;
         mAppTransitionState = APP_STATE_RUNNING;
+        notifyAppTransitionStartingLocked(
+                openingAppAnimator != null ? openingAppAnimator.mAppToken.token : null,
+                closingAppAnimator != null ? closingAppAnimator.mAppToken.token : null,
+                openingAppAnimator != null ? openingAppAnimator.animation : null,
+                closingAppAnimator != null ? closingAppAnimator.animation : null);
     }
 
     void clear() {
@@ -309,6 +316,38 @@
         setAppTransition(AppTransition.TRANSIT_UNSET);
         clear();
         setReady();
+        notifyAppTransitionCancelledLocked();
+    }
+
+    void registerListenerLocked(AppTransitionListener listener) {
+        mListeners.add(listener);
+    }
+
+    public void notifyAppTransitionFinishedLocked(AppWindowAnimator animator) {
+        IBinder token = animator != null ? animator.mAppToken.token : null;
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionFinishedLocked(token);
+        }
+    }
+
+    private void notifyAppTransitionPendingLocked() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionPendingLocked();
+        }
+    }
+
+    private void notifyAppTransitionCancelledLocked() {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionCancelledLocked();
+        }
+    }
+
+    private void notifyAppTransitionStartingLocked(IBinder openToken,
+            IBinder closeToken, Animation openAnimation, Animation closeAnimation) {
+        for (int i = 0; i < mListeners.size(); i++) {
+            mListeners.get(i).onAppTransitionStartingLocked(openToken, closeToken, openAnimation,
+                    closeAnimation);
+        }
     }
 
     private AttributeCache.Entry getCachedAnimations(WindowManager.LayoutParams lp) {
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 5c81126..a58f30d 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import android.graphics.Matrix;
-import android.os.RemoteException;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.view.Display;
@@ -142,6 +141,10 @@
         }
     }
 
+    public boolean isAnimating() {
+        return animation != null || mAppToken.inPendingTransaction;
+    }
+
     public void clearThumbnail() {
         if (thumbnail != null) {
             thumbnail.destroy();
@@ -312,23 +315,7 @@
         for (int i = 0; i < numAllAppWinAnimators; i++) {
             mAllAppWinAnimators.get(i).finishExit();
         }
-        if (mAppToken.mLaunchTaskBehind) {
-            try {
-                mService.mActivityManager.notifyLaunchTaskBehindComplete(mAppToken.token);
-            } catch (RemoteException e) {
-            }
-            mAppToken.mLaunchTaskBehind = false;
-        } else {
-            mAppToken.updateReportedVisibilityLocked();
-            if (mAppToken.mEnteringAnimation) {
-                mAppToken.mEnteringAnimation = false;
-                try {
-                    mService.mActivityManager.notifyEnterAnimationComplete(mAppToken.token);
-                } catch (RemoteException e) {
-                }
-            }
-        }
-
+        mService.mAppTransition.notifyAppTransitionFinishedLocked(this);
         return false;
     }
 
diff --git a/services/core/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java
index f1f5fe8..826fe97 100644
--- a/services/core/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java
@@ -16,14 +16,14 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface.OutOfResourcesException;
@@ -35,14 +35,17 @@
 
 class FocusedStackFrame {
     private static final String TAG = "FocusedStackFrame";
-    private static final int THICKNESS = 10;
+    private static final boolean DEBUG = false;
+    private static final int THICKNESS = 2;
     private static final float ALPHA = 0.3f;
 
     private final SurfaceControl mSurfaceControl;
     private final Surface mSurface = new Surface();
+    private final Paint mInnerPaint = new Paint();
+    private final Paint mOuterPaint = new Paint();
+    private final Rect mBounds = new Rect();
     private final Rect mLastBounds = new Rect();
-    final Rect mBounds = new Rect();
-    private final Rect mTmpDrawRect = new Rect();
+    private int mLayer = -1;
 
     public FocusedStackFrame(Display display, SurfaceSession session) {
         SurfaceControl ctrl = null;
@@ -60,83 +63,84 @@
         } catch (OutOfResourcesException e) {
         }
         mSurfaceControl = ctrl;
+
+        mInnerPaint.setStyle(Paint.Style.STROKE);
+        mInnerPaint.setStrokeWidth(THICKNESS);
+        mInnerPaint.setColor(Color.WHITE);
+        mOuterPaint.setStyle(Paint.Style.STROKE);
+        mOuterPaint.setStrokeWidth(THICKNESS);
+        mOuterPaint.setColor(Color.BLACK);
     }
 
-    private void draw(Rect bounds, int color) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "draw: bounds=" + bounds.toShortString() +
-                " color=" + Integer.toHexString(color));
-        mTmpDrawRect.set(bounds);
+    private void draw() {
+        if (mLastBounds.isEmpty()) {
+            // Currently unset. Set it.
+            mLastBounds.set(mBounds);
+        }
+
+        if (DEBUG) Slog.i(TAG, "draw: mBounds=" + mBounds + " mLastBounds=" + mLastBounds);
+
         Canvas c = null;
         try {
-            c = mSurface.lockCanvas(mTmpDrawRect);
+            c = mSurface.lockCanvas(mLastBounds);
         } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         } catch (Surface.OutOfResourcesException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         }
         if (c == null) {
+            if (DEBUG) Slog.w(TAG, "Canvas is null...");
             return;
         }
 
-        final int w = bounds.width();
-        final int h = bounds.height();
-
-        // Top
-        mTmpDrawRect.set(0, 0, w, THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Left (not including Top or Bottom stripe).
-        mTmpDrawRect.set(0, THICKNESS, THICKNESS, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Right (not including Top or Bottom stripe).
-        mTmpDrawRect.set(w - THICKNESS, THICKNESS, w, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Bottom
-        mTmpDrawRect.set(0, h - THICKNESS, w, h);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-
+        c.drawRect(0, 0, mBounds.width(), mBounds.height(), mOuterPaint);
+        c.drawRect(THICKNESS, THICKNESS, mBounds.width() - THICKNESS, mBounds.height() - THICKNESS,
+                mInnerPaint);
+        if (DEBUG) Slog.w(TAG, "c.width=" + c.getWidth() + " c.height=" + c.getHeight()
+                + " c.clip=" + c .getClipBounds());
         mSurface.unlockCanvasAndPost(c);
+        mLastBounds.set(mBounds);
     }
 
-    private void positionSurface(Rect bounds) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "positionSurface: bounds=" + bounds.toShortString());
-        mSurfaceControl.setSize(bounds.width(), bounds.height());
-        mSurfaceControl.setPosition(bounds.left, bounds.top);
+    private void setupSurface(boolean visible) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setupSurface");
+        SurfaceControl.openTransaction();
+        try {
+            if (visible) {
+                mSurfaceControl.setPosition(mBounds.left, mBounds.top);
+                mSurfaceControl.setSize(mBounds.width(), mBounds.height());
+                mSurfaceControl.show();
+            } else {
+                mSurfaceControl.hide();
+            }
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setupSurface");
+        }
+    }
+
+    void setVisibility(TaskStack stack) {
+        if (stack == null || stack.isFullscreen()) {
+            setupSurface(false);
+        } else {
+            stack.getBounds(mBounds);
+            setupSurface(true);
+            if (!mBounds.equals(mLastBounds)) {
+                draw();
+            }
+        }
     }
 
     // Note: caller responsible for being inside
     // Surface.openTransaction() / closeTransaction()
-    public void setVisibility(boolean on) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "setVisibility: on=" + on +
-                " mLastBounds=" + mLastBounds.toShortString() +
-                " mBounds=" + mBounds.toShortString());
-        if (mSurfaceControl == null) {
+    void setLayer(int layer) {
+        if (mLayer == layer) {
             return;
         }
-        if (on) {
-            if (!mLastBounds.equals(mBounds)) {
-                // Erase the previous rectangle.
-                positionSurface(mLastBounds);
-                draw(mLastBounds, Color.TRANSPARENT);
-                // Draw the latest rectangle.
-                positionSurface(mBounds);
-                draw(mBounds, Color.WHITE);
-                // Update the history.
-                mLastBounds.set(mBounds);
-            }
-            mSurfaceControl.show();
-        } else {
-            mSurfaceControl.hide();
-        }
-    }
-
-    public void setBounds(TaskStack stack) {
-        stack.getBounds(mBounds);
-        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
-    }
-
-    public void setLayer(int layer) {
-        mSurfaceControl.setLayer(layer);
+        mLayer = layer;
+        mSurfaceControl.setLayer(mLayer);
     }
 }
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index d68c056..487483e 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -461,6 +461,16 @@
         return mService.getWindowId(window);
     }
 
+    @Override
+    public void pokeDrawLock(IBinder window) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mService.pokeDrawLock(this, window);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     void windowAddedLocked() {
         if (mSurfaceSession == null) {
             if (WindowManagerService.localLOGV) Slog.v(
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a9b26e2..b8f26c9 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -72,6 +72,19 @@
         mService.mTaskIdToTask.delete(mTaskId);
     }
 
+    void moveTaskToStack(TaskStack stack, boolean toTop) {
+        if (stack == mStack) {
+            return;
+        }
+        if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: removing taskId=" + mTaskId
+                + " from stack=" + mStack);
+        EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeTask");
+        if (mStack != null) {
+            mStack.removeTask(this);
+        }
+        stack.addTask(this, toTop);
+    }
+
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 94fecc9..3e1c5ff 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,7 +26,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TypedValue;
-import android.view.Display;
 import android.view.Surface;
 
 import com.android.server.EventLogTags;
@@ -371,7 +370,7 @@
             for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
                 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
-                    mService.removeWindowInnerLocked(null, appWindows.get(winNdx));
+                    mService.removeWindowInnerLocked(appWindows.get(winNdx));
                     doAnotherLayoutPass = true;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index abf8412..a11963c 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -62,8 +62,12 @@
     final Context mContext;
     final WindowManagerPolicy mPolicy;
 
+    /** Is any window animating? */
     boolean mAnimating;
 
+    /** Is any app window animating? */
+    boolean mAppWindowAnimating;
+
     final Choreographer.FrameCallback mAnimationFrameCallback;
 
     /** Time of current animation step. Reset on each iteration */
@@ -158,7 +162,7 @@
                     final boolean wasAnimating = appAnimator.animation != null
                             && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                     if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                        mAnimating = true;
+                        mAnimating = mAppWindowAnimating = true;
                     } else if (wasAnimating) {
                         // stopped animating, do one more pass through the layout
                         setAppLayoutChanges(appAnimator,
@@ -177,7 +181,7 @@
                 final boolean wasAnimating = appAnimator.animation != null
                         && appAnimator.animation != AppWindowAnimator.sDummyAnimation;
                 if (appAnimator.stepAnimationLocked(mCurrentTime)) {
-                    mAnimating = true;
+                    mAnimating = mAppWindowAnimating = true;
                 } else if (wasAnimating) {
                     // stopped animating, do one more pass through the layout
                     setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
@@ -601,6 +605,7 @@
         mBulkUpdateParams = SET_ORIENTATION_CHANGE_COMPLETE;
         boolean wasAnimating = mAnimating;
         mAnimating = false;
+        mAppWindowAnimating = false;
         if (WindowManagerService.DEBUG_WINDOW_TRACE) {
             Slog.i(TAG, "!!! animate: entry time=" + mCurrentTime);
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dd4bbb7..fde0bd5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.am.ActivityStackSupervisor.HOME_STACK_ID;
 import static android.view.WindowManager.LayoutParams.*;
 
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -64,11 +65,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
@@ -127,7 +126,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
@@ -136,7 +134,6 @@
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.view.animation.Transformation;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -181,7 +178,6 @@
     static final boolean DEBUG_CONFIGURATION = false;
     static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
-    static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
@@ -194,6 +190,7 @@
     static final boolean DEBUG_TASK_MOVEMENT = false;
     static final boolean DEBUG_STACK = false;
     static final boolean DEBUG_DISPLAY = false;
+    static final boolean DEBUG_POWER = false;
     static final boolean SHOW_SURFACE_ALLOC = false;
     static final boolean SHOW_TRANSACTIONS = false;
     static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS;
@@ -332,6 +329,7 @@
     final boolean mHaveInputMethods;
 
     final boolean mHasPermanentDpad;
+    final long mDrawLockTimeoutMillis;
 
     final boolean mAllowBootMessages;
 
@@ -413,7 +411,7 @@
      * This is set when we have run out of memory, and will either be an empty
      * list or contain windows that need to be force removed.
      */
-    ArrayList<WindowState> mForceRemoves;
+    final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
 
     /**
      * Windows that clients are waiting to have drawn.
@@ -685,11 +683,11 @@
 
     final WindowAnimator mAnimator;
 
-    SparseArray<Task> mTaskIdToTask = new SparseArray<Task>();
+    SparseArray<Task> mTaskIdToTask = new SparseArray<>();
 
     /** All of the TaskStacks in the window manager, unordered. For an ordered list call
      * DisplayContent.getStacks(). */
-    SparseArray<TaskStack> mStackIdToStack = new SparseArray<TaskStack>();
+    SparseArray<TaskStack> mStackIdToStack = new SparseArray<>();
 
     private final PointerEventDispatcher mPointerEventDispatcher;
 
@@ -784,6 +782,35 @@
     // For example, when this flag is true, there will be no wallpaper service.
     final boolean mOnlyCore;
 
+    /** Listener to notify activity manager about app transitions. */
+    private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
+            = new WindowManagerInternal.AppTransitionListener() {
+
+        @Override
+        public void onAppTransitionFinishedLocked(IBinder token) {
+            AppWindowToken atoken = findAppWindowToken(token);
+            if (atoken == null) {
+                return;
+            }
+            if (atoken.mLaunchTaskBehind) {
+                try {
+                    mActivityManager.notifyLaunchTaskBehindComplete(atoken.token);
+                } catch (RemoteException e) {
+                }
+                atoken.mLaunchTaskBehind = false;
+            } else {
+                atoken.updateReportedVisibilityLocked();
+                if (atoken.mEnteringAnimation) {
+                    atoken.mEnteringAnimation = false;
+                    try {
+                        mActivityManager.notifyEnterAnimationComplete(atoken.token);
+                    } catch (RemoteException e) {
+                    }
+                }
+            }
+        }
+    };
+
     public static WindowManagerService main(final Context context,
             final InputManagerService im,
             final boolean haveInputMethods, final boolean showBootMsgs,
@@ -822,6 +849,8 @@
                 com.android.internal.R.bool.config_hasPermanentDpad);
         mInTouchMode = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_defaultInTouchMode);
+        mDrawLockTimeoutMillis = context.getResources().getInteger(
+                com.android.internal.R.integer.config_drawLockTimeoutMillis);
         mInputManager = inputManager; // Must be before createDisplayContentLocked.
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplaySettings = new DisplaySettings();
@@ -860,6 +889,7 @@
         mScreenFrozenLock.setReferenceCounted(false);
 
         mAppTransition = new AppTransition(context, mH);
+        mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
 
         mActivityManager = ActivityManagerNative.getDefault();
         mBatteryStats = BatteryStatsService.getService();
@@ -1736,10 +1766,7 @@
         }
     }
 
-    static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
-    static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
-
-    int adjustWallpaperWindowsLocked() {
+    boolean adjustWallpaperWindowsLocked() {
         mInnerFields.mWallpaperMayChange = false;
         boolean targetChanged = false;
 
@@ -1966,13 +1993,12 @@
 
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
-        int changed = 0;
+        boolean changed = false;
         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.
                 getDefaultDisplayContentLocked().layoutNeeded = true;
@@ -2033,7 +2059,7 @@
 
                 windows.add(insertionIndex, wallpaper);
                 mWindowsChanged = true;
-                changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
+                changed = true;
             }
         }
 
@@ -2654,7 +2680,7 @@
             }
         }
 
-        removeWindowInnerLocked(session, win);
+        removeWindowInnerLocked(win);
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && updateOrientationFromAppTokensLocked(false)) {
@@ -2664,7 +2690,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    void removeWindowInnerLocked(Session session, WindowState win) {
+    void removeWindowInnerLocked(WindowState win) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2674,7 +2700,7 @@
             WindowState cwin = win.mChildWindows.get(i);
             Slog.w(TAG, "Force-removing child win " + cwin + " from container "
                     + win);
-            removeWindowInnerLocked(cwin.mSession, cwin);
+            removeWindowInnerLocked(cwin);
         }
 
         win.mRemoved = true;
@@ -2939,6 +2965,15 @@
         }
     }
 
+    public void pokeDrawLock(Session session, IBinder token) {
+        synchronized (mWindowMap) {
+            WindowState window = windowForClientLocked(session, token, false);
+            if (window != null) {
+                window.pokeDrawLockLw(mDrawLockTimeoutMillis);
+            }
+        }
+    }
+
     public int relayoutWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int requestedWidth,
             int requestedHeight, int viewVisibility, int flags,
@@ -3781,6 +3816,9 @@
 
     private Configuration updateOrientationFromAppTokensLocked(
             Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
+        if (!mDisplayReady) {
+            return null;
+        }
         Configuration config = null;
 
         if (updateOrientationFromAppTokensLocked(false)) {
@@ -3799,20 +3837,19 @@
             // the value of the previous configuration.
             mTempConfiguration.setToDefaults();
             mTempConfiguration.fontScale = currentConfig.fontScale;
-            if (computeScreenConfigurationLocked(mTempConfiguration)) {
-                if (currentConfig.diff(mTempConfiguration) != 0) {
-                    mWaitingForConfig = true;
-                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                    displayContent.layoutNeeded = true;
-                    int anim[] = new int[2];
-                    if (displayContent.isDimming()) {
-                        anim[0] = anim[1] = 0;
-                    } else {
-                        mPolicy.selectRotationAnimationLw(anim);
-                    }
-                    startFreezingDisplayLocked(false, anim[0], anim[1]);
-                    config = new Configuration(mTempConfiguration);
+            computeScreenConfigurationLocked(mTempConfiguration);
+            if (currentConfig.diff(mTempConfiguration) != 0) {
+                mWaitingForConfig = true;
+                final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                displayContent.layoutNeeded = true;
+                int anim[] = new int[2];
+                if (displayContent.isDimming()) {
+                    anim[0] = anim[1] = 0;
+                } else {
+                    mPolicy.selectRotationAnimationLw(anim);
                 }
+                startFreezingDisplayLocked(false, anim[0], anim[1]);
+                config = new Configuration(mTempConfiguration);
             }
         }
 
@@ -3936,20 +3973,7 @@
         } else {
             stack = null;
         }
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame");
-        SurfaceControl.openTransaction();
-        try {
-            if (stack == null) {
-                mFocusedStackFrame.setVisibility(false);
-            } else {
-                mFocusedStackFrame.setBounds(stack);
-                final boolean multipleStacks = !stack.isFullscreen();
-                mFocusedStackFrame.setVisibility(multipleStacks);
-            }
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame");
-        }
+        mFocusedStackFrame.setVisibility(stack);
     }
 
     @Override
@@ -5065,6 +5089,7 @@
                     + " to " + (toTop ? "top" : "bottom"));
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "addTask: could not find taskId=" + taskId);
                 return;
             }
             TaskStack stack = mStackIdToStack.get(stackId);
@@ -5075,6 +5100,27 @@
         }
     }
 
+    public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
+        synchronized (mWindowMap) {
+            if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: moving taskId=" + taskId
+                    + " to stackId=" + stackId + " at " + (toTop ? "top" : "bottom"));
+            Task task = mTaskIdToTask.get(taskId);
+            if (task == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: could not find taskId=" + taskId);
+                return;
+            }
+            TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                if (DEBUG_STACK) Slog.i(TAG, "moveTaskToStack: could not find stackId=" + stackId);
+                return;
+            }
+            task.moveTaskToStack(stack, toTop);
+            final DisplayContent displayContent = stack.getDisplayContent();
+            displayContent.layoutNeeded = true;
+            performLayoutAndPlaceSurfacesLocked();
+        }
+    }
+
     /**
      * Re-sizes the specified stack and its containing windows.
      * Returns a {@link Configuration} object that contains configurations settings
@@ -5105,6 +5151,24 @@
         bounds.setEmpty();
     }
 
+    /** Returns the id of an application (non-home stack) stack that match the input bounds.
+     * -1 if no stack matches.*/
+    public int getStackIdWithBounds(Rect bounds) {
+        Rect stackBounds = new Rect();
+        synchronized (mWindowMap) {
+            for (int i = mStackIdToStack.size() - 1; i >= 0; --i) {
+                TaskStack stack = mStackIdToStack.valueAt(i);
+                if (stack.mStackId != HOME_STACK_ID) {
+                    stack.getBounds(stackBounds);
+                    if (stackBounds.equals(bounds)) {
+                        return stack.mStackId;
+                    }
+                }
+            }
+        }
+        return -1;
+    }
+
     /** 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.
@@ -6917,9 +6981,11 @@
 
     public Configuration computeNewConfiguration() {
         synchronized (mWindowMap) {
+            if (!mDisplayReady) {
+                return null;
+            }
             Configuration config = computeNewConfigurationLocked();
-            if (config == null && mWaitingForConfig) {
-                // Nothing changed but we are waiting for something... stop that!
+            if (mWaitingForConfig) {
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
                 performLayoutAndPlaceSurfacesLocked();
@@ -6931,9 +6997,7 @@
     Configuration computeNewConfigurationLocked() {
         Configuration config = new Configuration();
         config.fontScale = 0;
-        if (!computeScreenConfigurationLocked(config)) {
-            return null;
-        }
+        computeScreenConfigurationLocked(config);
         return config;
     }
 
@@ -7040,11 +7104,8 @@
         return sw;
     }
 
+    /** Do not call if mDisplayReady == false */
     DisplayInfo updateDisplayAndOrientationLocked() {
-        if (!mDisplayReady) {
-            return null;
-        }
-
         // TODO(multidisplay): For now, apply Configuration to main screen only.
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
 
@@ -7101,11 +7162,9 @@
         return displayInfo;
     }
 
-    boolean computeScreenConfigurationLocked(Configuration config) {
+    /** Do not call if mDisplayReady == false */
+    void computeScreenConfigurationLocked(Configuration config) {
         final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();
-        if (displayInfo == null) {
-            return false;
-        }
 
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -7190,8 +7249,6 @@
         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
         config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
         mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
-
-        return true;
     }
 
     public boolean isHardKeyboardAvailable() {
@@ -7931,16 +7988,16 @@
                     break;
 
                 case TAP_OUTSIDE_STACK: {
-//                    int stackId;
-//                    synchronized (mWindowMap) {
-//                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
-//                    }
-//                    if (stackId >= 0) {
-//                        try {
-//                            mActivityManager.setFocusedStack(stackId);
-//                        } catch (RemoteException e) {
-//                        }
-//                    }
+                    int stackId;
+                    synchronized (mWindowMap) {
+                        stackId = ((DisplayContent)msg.obj).stackIdFromPoint(msg.arg1, msg.arg2);
+                    }
+                    if (stackId >= 0) {
+                        try {
+                            mActivityManager.setFocusedStack(stackId);
+                        } catch (RemoteException e) {
+                        }
+                    }
                 }
                 break;
                 case NOTIFY_ACTIVITY_DRAWN:
@@ -8320,17 +8377,17 @@
     // displayContent must not be null
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
+        if (!mDisplayReady) {
+            return;
+        }
         configureDisplayPolicyLocked(displayContent);
         displayContent.layoutNeeded = true;
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
         mTempConfiguration.fontScale = mCurConfiguration.fontScale;
-        if (computeScreenConfigurationLocked(mTempConfiguration)) {
-            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
-                configChanged = true;
-            }
-        }
+        computeScreenConfigurationLocked(mTempConfiguration);
+        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
 
         if (configChanged) {
             mWaitingForConfig = true;
@@ -8631,29 +8688,24 @@
 
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
         mInLayout = true;
-        boolean recoveringMemory = false;
 
-        try {
-            if (mForceRemoves != null) {
-                recoveringMemory = true;
-                // Wait a little bit for things to settle down, and off we go.
-                for (int i=0; i<mForceRemoves.size(); i++) {
-                    WindowState ws = mForceRemoves.get(i);
-                    Slog.i(TAG, "Force removing: " + ws);
-                    removeWindowInnerLocked(ws.mSession, ws);
-                }
-                mForceRemoves = null;
-                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
-                Object tmp = new Object();
-                synchronized (tmp) {
-                    try {
-                        tmp.wait(250);
-                    } catch (InterruptedException e) {
-                    }
+        boolean recoveringMemory = false;
+        if (!mForceRemoves.isEmpty()) {
+            recoveringMemory = true;
+            // Wait a little bit for things to settle down, and off we go.
+            while (!mForceRemoves.isEmpty()) {
+                WindowState ws = mForceRemoves.remove(0);
+                Slog.i(TAG, "Force removing: " + ws);
+                removeWindowInnerLocked(ws);
+            }
+            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
+            Object tmp = new Object();
+            synchronized (tmp) {
+                try {
+                    tmp.wait(250);
+                } catch (InterruptedException e) {
                 }
             }
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception while force removing for memory", e);
         }
 
         try {
@@ -8905,7 +8957,6 @@
             if (mSkipAppTransitionAnimation) {
                 transit = AppTransition.TRANSIT_UNSET;
             }
-            mAppTransition.goodToGo();
             mStartingIconInTransition = false;
             mSkipAppTransitionAnimation = false;
 
@@ -9058,6 +9109,7 @@
                     for (int j = 0; j < N; j++) {
                         appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
                     }
+                    mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
                     mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
                 }
             }
@@ -9080,6 +9132,7 @@
                     appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
                 }
                 mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
                 if (animLp != null) {
                     int layer = -1;
@@ -9116,6 +9169,7 @@
                 if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
                     scheduleRemoveStartingWindowLocked(wtoken);
                 }
+                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
 
                 if (animLp != null) {
                     int layer = -1;
@@ -9200,6 +9254,7 @@
                 }
             }
 
+            mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
             mAppTransition.postAnimationCallback();
             mAppTransition.clear();
 
@@ -9329,14 +9384,12 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @param w WindowState this method is applied to.
-     * @param currentTime The time which animations use for calculating transitions.
+     *  @param w WindowState this method is applied to.
      * @param innerDw Width of app window.
      * @param innerDh Height of app window.
      */
-    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
-                                         final int innerDw, final int innerDh) {
+    private void handleNotObscuredLocked(final WindowState w,
+            final int innerDw, final int innerDh) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
@@ -9455,8 +9508,6 @@
                     + Debug.getCallers(3));
         }
 
-        final long currentTime = SystemClock.uptimeMillis();
-
         int i;
         boolean updateInputWindowsNeeded = false;
 
@@ -9547,8 +9598,7 @@
 
                     if ((displayContent.pendingLayoutChanges &
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                            (adjustWallpaperWindowsLocked() &
-                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                            adjustWallpaperWindowsLocked()) {
                         assignLayersLocked(windows);
                         displayContent.layoutNeeded = true;
                     }
@@ -9613,7 +9663,7 @@
                     // Update effect.
                     w.mObscured = mInnerFields.mObscured;
                     if (!mInnerFields.mObscured) {
-                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
+                        handleNotObscuredLocked(w, innerDw, innerDh);
                     }
 
                     if (stack != null && !stack.testDimmingTag()) {
@@ -9787,7 +9837,7 @@
                     defaultDisplay.pendingLayoutChanges);
         }
 
-        if (!mAnimator.mAnimating && mAppTransition.isRunning()) {
+        if (!mAnimator.mAppWindowAnimating && mAppTransition.isRunning()) {
             // We have finished the animation of an app transition.  To do
             // this, we have delayed a lot of operations like showing and
             // hiding apps, moving apps in Z-order, etc.  The app token list
@@ -9961,7 +10011,9 @@
             if (mAllowTheaterModeWakeFromLayout
                     || Settings.Global.getInt(mContext.getContentResolver(),
                         Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!");
+                if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                    Slog.v(TAG, "Turning screen on after layout!");
+                }
                 mPowerManager.wakeUp(SystemClock.uptimeMillis());
             }
             mTurnOnScreen = false;
@@ -9992,7 +10044,7 @@
             DisplayContentList displayList = new DisplayContentList();
             for (i = 0; i < N; i++) {
                 WindowState w = mPendingRemoveTmp[i];
-                removeWindowInnerLocked(w.mSession, w);
+                removeWindowInnerLocked(w);
                 final DisplayContent displayContent = w.getDisplayContent();
                 if (displayContent != null && !displayList.contains(displayContent)) {
                     displayList.add(displayContent);
@@ -10168,10 +10220,6 @@
         EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
                 winAnimator.mSession.mPid, operation);
 
-        if (mForceRemoves == null) {
-            mForceRemoves = new ArrayList<WindowState>();
-        }
-
         long callingIdentity = Binder.clearCallingIdentity();
         try {
             // There was some problem...   first, do a sanity check of the
@@ -10353,6 +10401,10 @@
                 + ", flags=" + win.mAttrs.flags
                 + ", canReceive=" + win.canReceiveKeys());
 
+            if (!win.canReceiveKeys()) {
+                continue;
+            }
+
             AppWindowToken wtoken = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
@@ -10362,10 +10414,6 @@
                 continue;
             }
 
-            if (!win.canReceiveKeys()) {
-                continue;
-            }
-
             // Descend through all of the app tokens and find the first that either matches
             // win.mAppToken (return win) or mFocusedApp (return null).
             if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
@@ -11627,5 +11675,12 @@
                 WindowManagerService.this.removeWindowToken(token);
             }
         }
+
+        @Override
+        public void registerAppTransitionListener(AppTransitionListener listener) {
+            synchronized (mWindowMap) {
+                mAppTransition.registerListenerLocked(listener);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index d58b2b0..04aea84 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -19,9 +19,9 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_CONFIGURATION;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
 import static com.android.server.wm.WindowManagerService.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerService.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
-
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -34,12 +34,15 @@
 
 import android.app.AppOpsManager;
 import android.os.Debug;
+import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.SystemClock;
+import android.os.WorkSource;
 import android.util.TimeUtils;
 import android.view.Display;
 import android.view.IWindowFocusObserver;
 import android.view.IWindowId;
+
 import com.android.server.input.InputWindowHandle;
 
 import android.content.Context;
@@ -343,6 +346,15 @@
     /** When true this window can be displayed on screens owther than mOwnerUid's */
     private boolean mShowToOwnerOnly;
 
+    /**
+     * Wake lock for drawing.
+     * Even though it's slightly more expensive to do so, we will use a separate wake lock
+     * for each app that is requesting to draw while dozing so that we can accurately track
+     * who is preventing the system from suspending.
+     * This lock is only acquired on first use.
+     */
+    PowerManager.WakeLock mDrawLock;
+
     WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token,
            WindowState attachedWindow, int appOp, int seq, WindowManager.LayoutParams a,
            int viewVisibility, final DisplayContent displayContent) {
@@ -1269,6 +1281,33 @@
         }
     }
 
+    public void pokeDrawLockLw(long timeout) {
+        if (isVisibleOrAdding()) {
+            if (mDrawLock == null) {
+                // We want the tag name to be somewhat stable so that it is easier to correlate
+                // in wake lock statistics.  So in particular, we don't want to include the
+                // window's hash code as in toString().
+                CharSequence tag = mAttrs.getTitle();
+                if (tag == null) {
+                    tag = mAttrs.packageName;
+                }
+                mDrawLock = mService.mPowerManager.newWakeLock(
+                        PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
+                mDrawLock.setReferenceCounted(false);
+                mDrawLock.setWorkSource(new WorkSource(mOwnerUid, mAttrs.packageName));
+            }
+            // Each call to acquire resets the timeout.
+            if (DEBUG_POWER) {
+                Slog.d(TAG, "pokeDrawLock: poking draw lock on behalf of visible window owned by "
+                        + mAttrs.packageName);
+            }
+            mDrawLock.acquire(timeout);
+        } else if (DEBUG_POWER) {
+            Slog.d(TAG, "pokeDrawLock: suppressed draw lock request for invisible window "
+                    + "owned by " + mAttrs.packageName);
+        }
+    }
+
     @Override
     public boolean isAlive() {
         return mClient.asBinder().isBinderAlive();
@@ -1642,6 +1681,9 @@
                     pw.print(" mWallpaperDisplayOffsetY=");
                     pw.println(mWallpaperDisplayOffsetY);
         }
+        if (mDrawLock != null) {
+            pw.println("mDrawLock=" + mDrawLock);
+        }
     }
 
     String makeInputChannelName() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a78bab4..89ed5b7 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -238,9 +238,7 @@
     boolean isAnimating() {
         return mAnimation != null
                 || (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)
-                || (mAppAnimator != null &&
-                        (mAppAnimator.animation != null
-                                || mAppAnimator.mAppToken.inPendingTransaction));
+                || (mAppAnimator != null && mAppAnimator.isAnimating());
     }
 
     /** Is the window animating the DummyAnimation? */
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index f0e02bc..57ed876 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,7 +39,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -320,5 +322,23 @@
             this.admin = admin;
             this.packageName = admin.getPackageName();
         }
+        public void dump(String prefix, PrintWriter pw) {
+            pw.println(prefix + "admin=" + admin);
+            pw.println(prefix + "name=" + name);
+            pw.println();
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        if (mDeviceOwner != null) {
+            pw.println(prefix + "Device Owner: ");
+            mDeviceOwner.dump(prefix + "  ", pw);
+        }
+        if (mProfileOwners != null) {
+            for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
+                pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
+                entry.getValue().dump(prefix + "  ", pw);
+            }
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7ff7827..770da5b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -100,6 +100,7 @@
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -1920,13 +1921,11 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordQuality != quality) {
@@ -1969,11 +1968,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLength != length) {
@@ -2016,11 +2013,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordHistoryLength != length) {
@@ -2063,14 +2058,10 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-            if (timeout < 0) {
-                throw new IllegalArgumentException("Timeout must be >= 0 ms");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
             // Calling this API automatically bumps the expiration date
@@ -2232,11 +2223,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordUpperCase != length) {
@@ -2276,11 +2265,9 @@
     }
 
     public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLowerCase != length) {
@@ -2323,11 +2310,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLetters != length) {
@@ -2370,11 +2355,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNumeric != length) {
@@ -2417,11 +2400,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordSymbols != length) {
@@ -2464,11 +2445,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNonLetter != length) {
@@ -2561,11 +2540,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who,
@@ -2772,11 +2749,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
             if (ap.maximumTimeToUnlock != timeMs) {
@@ -2955,9 +2930,7 @@
 
     @Override
     public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         }
@@ -3297,9 +3270,7 @@
             return null;
         }
         synchronized(this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
+            Preconditions.checkNotNull(who, "ComponentName is null");
 
             // Only check if owner has set global proxy. We don't allow other users to set it.
             DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -3435,12 +3406,10 @@
         if (!mHasFeature) {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Only owner can set storage encryption
             if (userHandle != UserHandle.USER_OWNER
                     || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
@@ -3571,11 +3540,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (ap.disableScreenCapture != disabled) {
@@ -3630,11 +3597,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             if (admin.requireAutoTime != required) {
@@ -3682,11 +3647,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
             if (ap.disableCamera != disabled) {
@@ -3731,12 +3694,10 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "disable keyguard features");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             if (ap.disabledKeyguardFeatures != which) {
@@ -3880,9 +3841,7 @@
 
     @Override
     public void clearDeviceOwner(String packageName) {
-        if (packageName == null) {
-            throw new NullPointerException("packageName is null");
-        }
+        Preconditions.checkNotNull(packageName, "packageName is null");
         try {
             int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
             if (uid != Binder.getCallingUid()) {
@@ -4007,12 +3966,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Check if this is the profile owner who is calling
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             int userId = UserHandle.getCallingUserId();
@@ -4034,12 +3990,8 @@
 
     @Override
     public void setProfileName(ComponentName who, String profileName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int userId = UserHandle.getCallingUserId();
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
-
         // Check if this is the profile owner (includes device owner).
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -4187,7 +4139,9 @@
 
         synchronized (this) {
             p.println("Current Device Policy Manager state:");
-
+            if (mDeviceOwner != null) {
+                mDeviceOwner.dump("  ", pw);
+            }
             int userCount = mUserData.size();
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -4215,12 +4169,9 @@
     @Override
     public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4237,12 +4188,9 @@
 
     @Override
     public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4259,12 +4207,9 @@
 
     @Override
     public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4281,15 +4226,11 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(admin, "admin is null");
+        Preconditions.checkNotNull(agent, "agent is null");
         final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "set trust agent configuration");
         synchronized (this) {
-            if (admin == null) {
-                throw new NullPointerException("admin is null");
-            }
-            if (agent == null) {
-                throw new NullPointerException("agent is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args));
@@ -4303,10 +4244,8 @@
         if (!mHasFeature) {
             return null;
         }
+        Preconditions.checkNotNull(agent, "agent null");
         enforceCrossUserPermission(userHandle);
-        if (agent == null) {
-            throw new NullPointerException("agent is null");
-        }
 
         synchronized (this) {
             final String componentName = agent.flattenToString();
@@ -4359,10 +4298,8 @@
 
     @Override
     public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userHandle = UserHandle.getCallingUserId();
@@ -4384,11 +4321,9 @@
     }
 
     public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4411,11 +4346,9 @@
     }
 
     public void clearCrossProfileIntentFilters(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
@@ -4485,9 +4418,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         if (packageList != null) {
             int userId = UserHandle.getCallingUserId();
@@ -4532,10 +4463,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4640,9 +4568,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         // TODO When InputMethodManager supports per user calls remove
         //      this restriction.
@@ -4685,10 +4611,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4761,10 +4684,8 @@
 
     @Override
     public UserHandle createUser(ComponentName who, String name) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4815,10 +4736,8 @@
 
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4832,10 +4751,8 @@
 
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4856,12 +4773,10 @@
 
     @Override
     public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4875,12 +4790,10 @@
 
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
         final int userHandle = user.getIdentifier();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName());
@@ -4982,11 +4895,9 @@
     @Override
     public boolean setApplicationHidden(ComponentName who, String packageName,
             boolean hidden) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5005,11 +4916,9 @@
 
     @Override
     public boolean isApplicationHidden(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5028,11 +4937,8 @@
 
     @Override
     public void enableSystemApp(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5073,11 +4979,8 @@
 
     @Override
     public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5144,10 +5047,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (disabled) {
@@ -5185,12 +5086,9 @@
     @Override
     public void setUninstallBlocked(ComponentName who, String packageName,
             boolean uninstallBlocked) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userId = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5237,10 +5135,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (admin.disableCallerId != disabled) {
@@ -5255,12 +5151,8 @@
         if (!mHasFeature) {
             return false;
         }
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             return admin.disableCallerId;
@@ -5281,13 +5173,11 @@
      * Sets which packages may enter lock task mode.
      *
      * This function can only be called by the device owner.
-     * @param components The list of components allowed to enter lock task mode.
+     * @param packages The list of packages allowed to enter lock task mode.
      */
     public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
@@ -5309,15 +5199,13 @@
      * This function returns the list of components allowed to start the task lock mode.
      */
     public String[] getLockTaskPackages(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
             DevicePolicyData policy = getUserData(userHandle);
-            return policy.mLockTaskPackages.toArray(new String[0]);
+            return policy.mLockTaskPackages.toArray(new String[policy.mLockTaskPackages.size()]);
         }
     }
 
@@ -5373,11 +5261,9 @@
     @Override
     public void setGlobalSetting(ComponentName who, String setting, String value) {
         final ContentResolver contentResolver = mContext.getContentResolver();
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
@@ -5396,13 +5282,11 @@
 
     @Override
     public void setSecureSetting(ComponentName who, String setting, String value) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         final ContentResolver contentResolver = mContext.getContentResolver();
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -5427,10 +5311,8 @@
 
     @Override
     public void setMasterVolumeMuted(ComponentName who, boolean on) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IAudioService iAudioService = IAudioService.Stub.asInterface(
@@ -5447,12 +5329,8 @@
 
     @Override
     public boolean isMasterVolumeMuted(ComponentName who) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             AudioManager audioManager =
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index c6f6b85..0aa8862 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -26,7 +26,7 @@
 import android.hardware.usb.UsbInterface;
 import android.media.AudioSystem;
 import android.media.IAudioService;
-import android.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceInfo;
 import android.os.FileObserver;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -153,7 +153,7 @@
     // audioDevice - the AudioDevice that was added or removed
     // enabled - if true, we're connecting a device (it's arrived), else disconnecting
     private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
-       if (DEBUG) {
+        if (DEBUG) {
             Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
         }
 
@@ -422,7 +422,7 @@
     }
 
     /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
-       if (DEBUG) {
+        if (DEBUG) {
           Slog.d(TAG, "deviceRemoved(): " + usbDevice);
         }
 
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 2fb6dbf..43c7336 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -31,7 +31,6 @@
 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;
@@ -732,6 +731,8 @@
                     id = com.android.internal.R.string.usb_mtp_notification_title;
                 } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_PTP)) {
                     id = com.android.internal.R.string.usb_ptp_notification_title;
+                } else if (containsFunction(mCurrentFunctions, UsbManager.USB_FUNCTION_MIDI)) {
+                    id = com.android.internal.R.string.usb_midi_notification_title;
                 } else if (containsFunction(mCurrentFunctions,
                         UsbManager.USB_FUNCTION_MASS_STORAGE)) {
                     id = com.android.internal.R.string.usb_cd_installer_notification_title;
diff --git a/services/usb/java/com/android/server/usb/UsbMidiDevice.java b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
index 396ed38..e17abc0 100644
--- a/services/usb/java/com/android/server/usb/UsbMidiDevice.java
+++ b/services/usb/java/com/android/server/usb/UsbMidiDevice.java
@@ -17,12 +17,12 @@
 package com.android.server.usb;
 
 import android.content.Context;
-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.media.midi.MidiDeviceInfo;
+import android.media.midi.MidiDeviceServer;
+import android.media.midi.MidiManager;
+import android.media.midi.MidiPort;
+import android.media.midi.MidiReceiver;
+import android.media.midi.MidiSender;
 import android.os.Bundle;
 import android.system.ErrnoException;
 import android.system.Os;
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 570f5fd..4600b72 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -80,6 +80,9 @@
      * ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could
      * collide with values generated on other phones or after a data wipe of a given phone.
      *
+     * Important: A non-unique identifier could cause non-deterministic call-log backup/restore
+     * behavior.
+     *
      * @return A service-specific unique identifier for this {@code PhoneAccountHandle}.
      */
     public String getId() {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6c5f1c6..bcc1ccc 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -83,6 +83,12 @@
             "android.telecom.action.SHOW_CALL_SETTINGS";
 
     /**
+     * The {@link android.content.Intent} action used to show the respond via SMS settings page.
+     */
+    public static final String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS =
+            "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
+
+    /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
      * @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 94691c0..dda9626 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.telecom.PhoneAccount;
 import android.util.Log;
 
 import com.android.internal.telecom.ITelecomService;
@@ -3765,7 +3766,7 @@
 
    /**
     * Returns the IMS Registration Status
-    *@hide
+    * @hide
     */
    public boolean isImsRegistered() {
        try {
@@ -4116,4 +4117,21 @@
                     ServiceState.rilRadioTechnologyToString(type));
         }
     }
+
+    /**
+     * Returns the subscription ID for the given phone account.
+     * @hide
+     */
+    public int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
+        int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                retval = service.getSubIdForPhoneAccount(phoneAccount);
+            }
+        } catch (RemoteException e) {
+        }
+
+        return retval;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bf3ee09..62c8746 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.telecom.PhoneAccount;
 import android.telephony.CellInfo;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.NeighboringCellInfo;
@@ -879,4 +880,9 @@
       *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
       */
     String getDeviceId();
+
+    /**
+     * Returns the subscription ID associated with the specified PhoneAccount.
+     */
+    int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
 }
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index b8eaa2d..8af4f50 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -155,7 +155,7 @@
         return self.raw
 
 
-def parse_api(f):
+def _parse_stream(f, clazz_cb=None):
     line = 0
     api = {}
     pkg = None
@@ -163,7 +163,7 @@
     blame = None
 
     re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
-    for raw in f.readlines():
+    for raw in f:
         line += 1
         raw = raw.rstrip()
         match = re_blame.match(raw)
@@ -176,8 +176,13 @@
         if raw.startswith("package"):
             pkg = Package(line, raw, blame)
         elif raw.startswith("  ") and raw.endswith("{"):
+            # When provided with class callback, we treat as incremental
+            # parse and don't build up entire API
+            if clazz and clazz_cb:
+                clazz_cb(clazz)
             clazz = Class(pkg, line, raw, blame)
-            api[clazz.fullname] = clazz
+            if not clazz_cb:
+                api[clazz.fullname] = clazz
         elif raw.startswith("    ctor"):
             clazz.ctors.append(Method(clazz, line, raw, blame))
         elif raw.startswith("    method"):
@@ -185,19 +190,16 @@
         elif raw.startswith("    field"):
             clazz.fields.append(Field(clazz, line, raw, blame))
 
+    # Handle last trailing class
+    if clazz and clazz_cb:
+        clazz_cb(clazz)
+
     return api
 
 
-def parse_api_file(fn):
-    with open(fn) as f:
-        return parse_api(f)
-
-
 class Failure():
     def __init__(self, sig, clazz, detail, error, rule, msg):
         self.sig = sig
-        self.clazz = clazz
-        self.detail = detail
         self.error = error
         self.rule = rule
         self.msg = msg
@@ -253,7 +255,7 @@
     for f in clazz.fields:
         if "static" in f.split and "final" in f.split:
             if re.match("[A-Z0-9_]+", f.name) is None:
-                error(clazz, f, "C2", "Constant field names should be FOO_NAME")
+                error(clazz, f, "C2", "Constant field names must be FOO_NAME")
 
 
 def verify_enums(clazz):
@@ -269,7 +271,7 @@
     if re.match("android\.R\.[a-z]+", clazz.fullname): return
 
     if re.search("[A-Z]{2,}", clazz.name) is not None:
-        warn(clazz, None, "S1", "Class name style should be Mtp not MTP")
+        warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
     if re.match("[^A-Z]", clazz.name):
         error(clazz, None, "S1", "Class must start with uppercase char")
 
@@ -282,7 +284,7 @@
 
     for m in clazz.methods:
         if re.search("[A-Z]{2,}", m.name) is not None:
-            warn(clazz, m, "S1", "Method name style should be getMtu() instead of getMTU()")
+            warn(clazz, m, "S1", "Method names with acronyms should be getMtu() instead of getMTU()")
         if re.match("[^a-z]", m.name):
             error(clazz, m, "S1", "Method name must start with lowercase char")
 
@@ -294,13 +296,13 @@
     if clazz.fullname == "android.speech.tts.SynthesisCallback": return
 
     if clazz.name.endswith("Callbacks"):
-        error(clazz, None, "L1", "Class name must not be plural")
+        error(clazz, None, "L1", "Callback class names should be singular")
     if clazz.name.endswith("Observer"):
         warn(clazz, None, "L1", "Class should be named FooCallback")
 
     if clazz.name.endswith("Callback"):
         if "interface" in clazz.split:
-            error(clazz, None, "CL3", "Callback must be abstract class to enable extension in future API levels")
+            error(clazz, None, "CL3", "Callbacks must be abstract class to enable extension in future API levels")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
@@ -316,7 +318,7 @@
 
     if clazz.name.endswith("Listener"):
         if " abstract class " in clazz.raw:
-            error(clazz, None, "L1", "Listener should be an interface, otherwise renamed Callback")
+            error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
@@ -325,7 +327,7 @@
         if len(clazz.methods) == 1 and clazz.name.startswith("On"):
             m = clazz.methods[0]
             if (m.name + "Listener").lower() != clazz.name.lower():
-                error(clazz, m, "L1", "Single listener method name should match class name")
+                error(clazz, m, "L1", "Single listener method name must match class name")
 
 
 def verify_actions(clazz):
@@ -412,10 +414,10 @@
     """Verify that no protected methods or fields are allowed."""
     for m in clazz.methods:
         if "protected" in m.split:
-            error(clazz, m, "M7", "No protected methods; must be public")
+            error(clazz, m, "M7", "Protected methods not allowed; must be public")
     for f in clazz.fields:
         if "protected" in f.split:
-            error(clazz, f, "M7", "No protected fields; must be public")
+            error(clazz, f, "M7", "Protected fields not allowed; must be public")
 
 
 def verify_fields(clazz):
@@ -449,10 +451,10 @@
 
         if not "static" in f.split:
             if not re.match("[a-z]([a-zA-Z]+)?", f.name):
-                error(clazz, f, "S1", "Non-static fields must be named with myField style")
+                error(clazz, f, "S1", "Non-static fields must be named using myField style")
 
         if re.match("[ms][A-Z]", f.name):
-            error(clazz, f, "F1", "Don't expose your internal objects")
+            error(clazz, f, "F1", "Internal objects must not be exposed")
 
         if re.match("[A-Z_]+", f.name):
             if "static" not in f.split or "final" not in f.split:
@@ -496,7 +498,7 @@
     """Verify synchronized methods aren't exposed."""
     for m in clazz.methods:
         if "synchronized" in m.split:
-            error(clazz, m, "M5", "Internal lock exposed")
+            error(clazz, m, "M5", "Internal locks must not be exposed")
 
 
 def verify_intent_builder(clazz):
@@ -508,7 +510,7 @@
             if m.name.startswith("create") and m.name.endswith("Intent"):
                 pass
             else:
-                error(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")
+                error(clazz, m, "FW1", "Methods creating an Intent must be named createFooIntent()")
 
 
 def verify_helper_classes(clazz):
@@ -537,7 +539,7 @@
             if f.name == "PROVIDER_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface name; expected %s" % (clazz.fullname))
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
 
     if "extends android.content.BroadcastReceiver" in clazz.raw:
         test_methods = True
@@ -578,11 +580,11 @@
         if m.name.startswith("clear"): continue
 
         if m.name.startswith("with"):
-            warn(clazz, m, None, "Builder methods names should follow setFoo() style")
+            warn(clazz, m, None, "Builder methods names should use setFoo() style")
 
         if m.name.startswith("set"):
             if not m.typ.endswith(clazz.fullname):
-                warn(clazz, m, "M4", "Methods should return the builder")
+                warn(clazz, m, "M4", "Methods must return the builder object")
 
     if not has_build:
         warn(clazz, None, None, "Missing build() method")
@@ -591,13 +593,13 @@
 def verify_aidl(clazz):
     """Catch people exposing raw AIDL."""
     if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw:
-        error(clazz, None, None, "Exposing raw AIDL interface")
+        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
 
 
 def verify_internal(clazz):
     """Catch people exposing internal classes."""
     if clazz.pkg.name.startswith("com.android"):
-        error(clazz, None, None, "Exposing internal class")
+        error(clazz, None, None, "Internal classes must not be exposed")
 
 
 def verify_layering(clazz):
@@ -644,26 +646,44 @@
                 warn(clazz, m, "FW6", "Method argument type violates package layering")
 
 
-def verify_boolean(clazz, api):
-    """Catches people returning boolean from getFoo() style methods.
-    Ignores when matching setFoo() is present."""
+def verify_boolean(clazz):
+    """Verifies that boolean accessors are named correctly.
+    For example, hasFoo() and setHasFoo()."""
 
-    methods = [ m.name for m in clazz.methods ]
+    def is_get(m): return len(m.args) == 0 and m.typ == "boolean"
+    def is_set(m): return len(m.args) == 1 and m.args[0] == "boolean"
 
-    builder = clazz.fullname + ".Builder"
-    builder_methods = []
-    if builder in api:
-        builder_methods = [ m.name for m in api[builder].methods ]
+    gets = [ m for m in clazz.methods if is_get(m) ]
+    sets = [ m for m in clazz.methods if is_set(m) ]
+
+    def error_if_exists(methods, trigger, expected, actual):
+        for m in methods:
+            if m.name == actual:
+                error(clazz, m, "M6", "Symmetric method for %s must be named %s" % (trigger, expected))
 
     for m in clazz.methods:
-        if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
-            setter = "set" + m.name[3:]
-            if setter in methods:
-                pass
-            elif builder is not None and setter in builder_methods:
-                pass
-            else:
-                warn(clazz, m, None, "Methods returning boolean should be named isFoo, hasFoo, areFoo")
+        if is_get(m):
+            if re.match("is[A-Z]", m.name):
+                target = m.name[2:]
+                expected = "setIs" + target
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+            elif re.match("has[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "setHas" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "set" + target)
+            elif re.match("get[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "set" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+
+        if is_set(m):
+            if re.match("set[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "get" + target
+                error_if_exists(sets, m.name, expected, "is" + target)
+                error_if_exists(sets, m.name, expected, "has" + target)
 
 
 def verify_collections(clazz):
@@ -674,10 +694,10 @@
            "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
     for m in clazz.methods:
         if m.typ in bad:
-            error(clazz, m, "CL2", "Return type is concrete collection; should be interface")
+            error(clazz, m, "CL2", "Return type is concrete collection; must be higher-level interface")
         for arg in m.args:
             if arg in bad:
-                error(clazz, m, "CL2", "Argument is concrete collection; should be interface")
+                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
 
 
 def verify_flags(clazz):
@@ -740,7 +760,7 @@
     if not clazz.name.endswith("Manager"): return
 
     for c in clazz.ctors:
-        error(clazz, c, None, "Managers should always be obtained from Context")
+        error(clazz, c, None, "Managers must always be obtained from Context")
 
 
 def verify_boxed(clazz):
@@ -751,18 +771,18 @@
     for c in clazz.ctors:
         for arg in c.args:
             if arg in boxed:
-                error(clazz, c, None, "Must avoid boxed primitives")
+                error(clazz, c, "M11", "Must avoid boxed primitives")
 
     for f in clazz.fields:
         if f.typ in boxed:
-            error(clazz, f, None, "Must avoid boxed primitives")
+            error(clazz, f, "M11", "Must avoid boxed primitives")
 
     for m in clazz.methods:
         if m.typ in boxed:
-            error(clazz, m, None, "Must avoid boxed primitives")
+            error(clazz, m, "M11", "Must avoid boxed primitives")
         for arg in m.args:
             if arg in boxed:
-                error(clazz, m, None, "Must avoid boxed primitives")
+                error(clazz, m, "M11", "Must avoid boxed primitives")
 
 
 def verify_static_utils(clazz):
@@ -791,7 +811,7 @@
         if "deprecated" in m.split: continue
         overloads[m.name].append(m)
 
-    for name, methods in overloads.iteritems():
+    for name, methods in overloads.items():
         if len(methods) <= 1: continue
 
         # Look for arguments common across all overloads
@@ -875,70 +895,117 @@
             if "android.os.Handler" in m.args:
                 takes_handler = True
         if not takes_handler:
-            error(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
+            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
 
 
 def verify_context_first(clazz):
     """Verifies that methods accepting a Context keep it the first argument."""
-    for m in clazz.ctors:
-        if len(m.args) > 1:
-            if "android.content.Context" in m.args[1:]:
-                error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
-
-    for m in clazz.methods:
-        if len(m.args) > 1:
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if len(m.args) > 1 and m.args[0] != "android.content.Context":
             if "android.content.Context" in m.args[1:]:
                 error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
 
 
-def verify_style(api):
-    """Find all style issues in the given API level."""
+def verify_listener_last(clazz):
+    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if "Listener" in m.name or "Callback" in m.name: continue
+        found = False
+        for a in m.args:
+            if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
+                found = True
+            elif found and a != "android.os.Handler":
+                warn(clazz, m, "M3", "Listeners should always be at end of argument list")
+
+
+def verify_resource_names(clazz):
+    """Verifies that resource names have consistent case."""
+    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+    # Resources defined by files are foo_bar_baz
+    if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
+        for f in clazz.fields:
+            if re.match("[a-z1-9_]+$", f.name): continue
+            error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
+
+    # Resources defined inside files are fooBarBaz
+    if clazz.name in ["array","attr","id","bool","fraction","integer"]:
+        for f in clazz.fields:
+            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("layout_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("state_[a-z_]*$", f.name): continue
+
+            if re.match("[a-z][a-zA-Z1-9]*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be fooBarBaz style")
+
+    # Styles are FooBar_Baz
+    if clazz.name in ["style"]:
+        for f in clazz.fields:
+            if re.match("[A-Z][A-Za-z1-9]+(_[A-Z][A-Za-z1-9]+?)*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
+
+
+def examine_clazz(clazz):
+    """Find all style issues in the given class."""
+    if clazz.pkg.name.startswith("java"): return
+    if clazz.pkg.name.startswith("junit"): return
+    if clazz.pkg.name.startswith("org.apache"): return
+    if clazz.pkg.name.startswith("org.xml"): return
+    if clazz.pkg.name.startswith("org.json"): return
+    if clazz.pkg.name.startswith("org.w3c"): return
+
+    verify_constants(clazz)
+    verify_enums(clazz)
+    verify_class_names(clazz)
+    verify_method_names(clazz)
+    verify_callbacks(clazz)
+    verify_listeners(clazz)
+    verify_actions(clazz)
+    verify_extras(clazz)
+    verify_equals(clazz)
+    verify_parcelable(clazz)
+    verify_protected(clazz)
+    verify_fields(clazz)
+    verify_register(clazz)
+    verify_sync(clazz)
+    verify_intent_builder(clazz)
+    verify_helper_classes(clazz)
+    verify_builder(clazz)
+    verify_aidl(clazz)
+    verify_internal(clazz)
+    verify_layering(clazz)
+    verify_boolean(clazz)
+    verify_collections(clazz)
+    verify_flags(clazz)
+    verify_exception(clazz)
+    verify_google(clazz)
+    verify_bitset(clazz)
+    verify_manager(clazz)
+    verify_boxed(clazz)
+    verify_static_utils(clazz)
+    verify_overload_args(clazz)
+    verify_callback_handlers(clazz)
+    verify_context_first(clazz)
+    verify_listener_last(clazz)
+    verify_resource_names(clazz)
+
+
+def examine_stream(stream):
+    """Find all style issues in the given API stream."""
     global failures
+    failures = {}
+    _parse_stream(stream, examine_clazz)
+    return failures
 
+
+def examine_api(api):
+    """Find all style issues in the given parsed API."""
+    global failures
     failures = {}
     for key in sorted(api.keys()):
-        clazz = api[key]
-
-        if clazz.pkg.name.startswith("java"): continue
-        if clazz.pkg.name.startswith("junit"): continue
-        if clazz.pkg.name.startswith("org.apache"): continue
-        if clazz.pkg.name.startswith("org.xml"): continue
-        if clazz.pkg.name.startswith("org.json"): continue
-        if clazz.pkg.name.startswith("org.w3c"): continue
-
-        verify_constants(clazz)
-        verify_enums(clazz)
-        verify_class_names(clazz)
-        verify_method_names(clazz)
-        verify_callbacks(clazz)
-        verify_listeners(clazz)
-        verify_actions(clazz)
-        verify_extras(clazz)
-        verify_equals(clazz)
-        verify_parcelable(clazz)
-        verify_protected(clazz)
-        verify_fields(clazz)
-        verify_register(clazz)
-        verify_sync(clazz)
-        verify_intent_builder(clazz)
-        verify_helper_classes(clazz)
-        verify_builder(clazz)
-        verify_aidl(clazz)
-        verify_internal(clazz)
-        verify_layering(clazz)
-        verify_boolean(clazz, api)
-        verify_collections(clazz)
-        verify_flags(clazz)
-        verify_exception(clazz)
-        verify_google(clazz)
-        verify_bitset(clazz)
-        verify_manager(clazz)
-        verify_boxed(clazz)
-        verify_static_utils(clazz)
-        verify_overload_args(clazz)
-        verify_callback_handlers(clazz)
-        verify_context_first(clazz)
-
+        examine_clazz(api[key])
     return failures
 
 
@@ -998,18 +1065,20 @@
 
 
 if __name__ == "__main__":
-    cur = parse_api_file(sys.argv[1])
-    cur_fail = verify_style(cur)
+    with open(sys.argv[1]) as f:
+        cur_fail = examine_stream(f)
 
     if len(sys.argv) > 2:
-        prev = parse_api_file(sys.argv[2])
-        prev_fail = verify_style(prev)
+        with open(sys.argv[2]) as f:
+            prev_fail = examine_stream(f)
 
         # ignore errors from previous API level
         for p in prev_fail:
             if p in cur_fail:
                 del cur_fail[p]
 
+        """
+        # NOTE: disabled because of memory pressure
         # look for compatibility issues
         compat_fail = verify_compat(cur, prev)
 
@@ -1017,7 +1086,7 @@
         for f in sorted(compat_fail):
             print compat_fail[f]
             print
-
+        """
 
     print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
     for f in sorted(cur_fail):
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 36102f1..7e4ff69 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -179,7 +179,7 @@
                         XmlPullParser parser = ParserFactory.create(f);
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
-                                parser, bridgeContext, false);
+                                parser, bridgeContext, value.isFramework());
 
                         return inflate(bridgeParser, root);
                     } catch (Exception e) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
index 62a03e1..4289689 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -206,4 +206,9 @@
         // pass for now.
         return null;
     }
+
+    @Override
+    public void pokeDrawLock(IBinder window) {
+        // pass for now.
+    }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
index e00ea6a..51a0104 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/SessionParamsFlags.java
@@ -29,6 +29,8 @@
 
     public static final SessionParams.Key<String> FLAG_KEY_ROOT_TAG =
             new SessionParams.Key<String>("rootTag", String.class);
+    public static final SessionParams.Key<Boolean> FLAG_KEY_DISABLE_BITMAP_CACHING =
+            new SessionParams.Key<Boolean>("disableBitmapCaching", Boolean.class);
 
     // Disallow instances.
     private SessionParamsFlags() {}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index 3a0321a..c34f9b5 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -35,6 +35,7 @@
 import java.awt.Color;
 import java.awt.Composite;
 import java.awt.Graphics2D;
+import java.awt.Rectangle;
 import java.awt.RenderingHints;
 import java.awt.Shape;
 import java.awt.geom.AffineTransform;
@@ -615,8 +616,22 @@
                 return;
             }
 
-            int width = layer.getImage().getWidth();
-            int height = layer.getImage().getHeight();
+            int width;
+            int height;
+            Rectangle clipBounds = originalGraphics.getClipBounds();
+            if (clipBounds != null) {
+                if (clipBounds.width == 0 || clipBounds.height == 0) {
+                    // Clip is 0 so no need to paint anything.
+                    return;
+                }
+                // If we have clipBounds available, use them as they will always be
+                // smaller than the full layer size.
+                width = clipBounds.width;
+                height = clipBounds.height;
+            } else {
+                width = layer.getImage().getWidth();
+                height = layer.getImage().getHeight();
+            }
 
             // Create a temporary image to which the color filter will be applied.
             BufferedImage image = new BufferedImage(width, height,
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 84ee914..875cc87 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
@@ -551,7 +551,14 @@
                 // draw the views
                 // create the BufferedImage into which the layout will be rendered.
                 boolean newImage = false;
-                if (newRenderSize || mCanvas == null) {
+
+                // When disableBitmapCaching is true, we do not reuse mImage and
+                // we create a new one in every render.
+                // This is useful when mImage is just a wrapper of Graphics2D so
+                // it doesn't get cached.
+                boolean disableBitmapCaching = Boolean.TRUE.equals(params.getFlag(
+                    SessionParamsFlags.FLAG_KEY_DISABLE_BITMAP_CACHING));
+                if (newRenderSize || mCanvas == null || disableBitmapCaching) {
                     if (params.getImageFactory() != null) {
                         mImage = params.getImageFactory().getImage(
                                 mMeasuredScreenWidth,
@@ -578,8 +585,12 @@
                     Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
                             true /*isMutable*/, hardwareConfig.getDensity());
 
-                    // create a Canvas around the Android bitmap
-                    mCanvas = new Canvas(bitmap);
+                    if (mCanvas == null) {
+                        // create a Canvas around the Android bitmap
+                        mCanvas = new Canvas(bitmap);
+                    } else {
+                        mCanvas.setBitmap(bitmap);
+                    }
                     mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
                 }