Merge "A new test for AnimatorSet's clone"
diff --git a/Android.mk b/Android.mk
index 40da134..505b12d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -160,6 +160,7 @@
 	core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
+	core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlCallback.aidl \
 	core/java/android/hardware/hdmi/IHdmiControlService.aidl \
@@ -172,6 +173,7 @@
 	core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl \
 	core/java/android/hardware/input/IInputManager.aidl \
 	core/java/android/hardware/input/IInputDevicesChangedListener.aidl \
+	core/java/android/hardware/input/ITabletModeChangedListener.aidl \
 	core/java/android/hardware/location/IActivityRecognitionHardware.aidl \
 	core/java/android/hardware/location/IActivityRecognitionHardwareClient.aidl \
 	core/java/android/hardware/location/IActivityRecognitionHardwareSink.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 48be749..6e44d77 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -235,6 +235,7 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
 $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/DocumentsUI_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 df74b45..d829272 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -241,10 +241,10 @@
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
     field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
     field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
-    field public static final int activityHeight = 16844019; // 0x10104f3
+    field public static final int activityHeight = 16844021; // 0x10104f5
     field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
-    field public static final int activityWidth = 16844018; // 0x10104f2
+    field public static final int activityWidth = 16844020; // 0x10104f4
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -786,6 +786,7 @@
     field public static final int listChoiceIndicatorSingle = 16843289; // 0x1010219
     field public static final int listDivider = 16843284; // 0x1010214
     field public static final int listDividerAlertDialog = 16843525; // 0x1010305
+    field public static final int listMenuViewStyle = 16844018; // 0x10104f2
     field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
     field public static final int listPreferredItemHeight = 16842829; // 0x101004d
     field public static final int listPreferredItemHeightLarge = 16843654; // 0x1010386
@@ -991,6 +992,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1148,6 +1150,7 @@
     field public static final int strokeLineJoin = 16843788; // 0x101040c
     field public static final int strokeMiterLimit = 16843789; // 0x101040d
     field public static final int strokeWidth = 16843783; // 0x1010407
+    field public static final int subMenuArrow = 16844019; // 0x10104f3
     field public static final int submitBackground = 16843912; // 0x1010488
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -3477,14 +3480,14 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
-    method public final void setProgress(int);
-    method public final void setProgressBarIndeterminate(boolean);
-    method public final void setProgressBarIndeterminateVisibility(boolean);
-    method public final void setProgressBarVisibility(boolean);
+    method public final deprecated void setProgress(int);
+    method public final deprecated void setProgressBarIndeterminate(boolean);
+    method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
+    method public final deprecated void setProgressBarVisibility(boolean);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
-    method public final void setSecondaryProgress(int);
+    method public final deprecated void setSecondaryProgress(int);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
@@ -9663,12 +9666,14 @@
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
+    method public android.util.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
     method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
     method public void setLocale(java.util.Locale);
+    method public void setLocales(android.util.LocaleList);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
@@ -9742,7 +9747,7 @@
     field public int hardKeyboardHidden;
     field public int keyboard;
     field public int keyboardHidden;
-    field public java.util.Locale locale;
+    field public deprecated java.util.Locale locale;
     field public int mcc;
     field public int mnc;
     field public int navigation;
@@ -11586,6 +11591,7 @@
     method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
     method public void getTextBounds(char[], int, int, android.graphics.Rect);
     method public java.util.Locale getTextLocale();
+    method public android.util.LocaleList getTextLocales();
     method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
     method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
     method public float getTextScaleX();
@@ -11641,6 +11647,7 @@
     method public void setSubpixelText(boolean);
     method public void setTextAlign(android.graphics.Paint.Align);
     method public void setTextLocale(java.util.Locale);
+    method public void setTextLocales(android.util.LocaleList);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSkewX(float);
@@ -12296,6 +12303,7 @@
     method public int getIntrinsicWidth();
     method public int getLayoutDirection();
     method public final int getLevel();
+    method public final float getLevelFloat();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
     method public abstract int getOpacity();
@@ -12315,6 +12323,7 @@
     method protected void onBoundsChange(android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
+    method protected boolean onLevelChange(float);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
@@ -12332,12 +12341,15 @@
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
+    method public final boolean setLevel(float);
     method public boolean setState(int[]);
     method public void setTint(int);
     method public void setTintList(android.content.res.ColorStateList);
     method public void setTintMode(android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(java.lang.Runnable);
+    field public static final int MAX_LEVEL = 10000; // 0x2710
+    field public static final float MAX_LEVEL_FLOAT = 10000.0f;
   }
 
   public static abstract interface Drawable.Callback {
@@ -18115,7 +18127,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public boolean sendObject(int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
@@ -18164,6 +18176,7 @@
     method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+    method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
     method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -34200,11 +34213,16 @@
 
   public final class LocaleList {
     ctor public LocaleList();
+    ctor public LocaleList(java.util.Locale);
     ctor public LocaleList(java.util.Locale[]);
+    method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getDefault();
+    method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getPrimary();
     method public boolean isEmpty();
     method public int size();
+    method public java.lang.String toLanguageTags();
   }
 
   public final class Log {
@@ -35352,6 +35370,7 @@
     field public static final int KEYCODE_SLEEP = 223; // 0xdf
     field public static final int KEYCODE_SOFT_LEFT = 1; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = 2; // 0x2
+    field public static final int KEYCODE_SOFT_SLEEP = 276; // 0x114
     field public static final int KEYCODE_SPACE = 62; // 0x3e
     field public static final int KEYCODE_STAR = 17; // 0x11
     field public static final int KEYCODE_STB_INPUT = 180; // 0xb4
@@ -37360,23 +37379,23 @@
     field public static final int FEATURE_CONTENT_TRANSITIONS = 12; // 0xc
     field public static final int FEATURE_CONTEXT_MENU = 6; // 0x6
     field public static final int FEATURE_CUSTOM_TITLE = 7; // 0x7
-    field public static final int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
+    field public static final deprecated int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
     field public static final int FEATURE_LEFT_ICON = 3; // 0x3
     field public static final int FEATURE_NO_TITLE = 1; // 0x1
     field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
-    field public static final int FEATURE_PROGRESS = 2; // 0x2
+    field public static final deprecated int FEATURE_PROGRESS = 2; // 0x2
     field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
     field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
     field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
     field public static final java.lang.String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "android:navigation:background";
-    field public static final int PROGRESS_END = 10000; // 0x2710
-    field public static final int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
-    field public static final int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
-    field public static final int PROGRESS_SECONDARY_END = 30000; // 0x7530
-    field public static final int PROGRESS_SECONDARY_START = 20000; // 0x4e20
-    field public static final int PROGRESS_START = 0; // 0x0
-    field public static final int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
-    field public static final int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
+    field public static final deprecated int PROGRESS_END = 10000; // 0x2710
+    field public static final deprecated int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
+    field public static final deprecated int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
+    field public static final deprecated int PROGRESS_SECONDARY_END = 30000; // 0x7530
+    field public static final deprecated int PROGRESS_SECONDARY_START = 20000; // 0x4e20
+    field public static final deprecated int PROGRESS_START = 0; // 0x0
+    field public static final deprecated int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
+    field public static final deprecated int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
     field public static final java.lang.String STATUS_BAR_BACKGROUND_TRANSITION_NAME = "android:status:background";
   }
 
@@ -41712,6 +41731,7 @@
     method public java.lang.CharSequence getText();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
+    method public android.util.LocaleList getTextLocales();
     method public float getTextScaleX();
     method public float getTextSize();
     method public int getTotalPaddingBottom();
@@ -41824,6 +41844,7 @@
     method public final void setTextKeepState(java.lang.CharSequence);
     method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
     method public void setTextLocale(java.util.Locale);
+    method public void setTextLocales(android.util.LocaleList);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSize(int, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index bcae74b..5905056 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -333,10 +333,10 @@
     field public static final int activatedBackgroundIndicator = 16843517; // 0x10102fd
     field public static final int activityCloseEnterAnimation = 16842938; // 0x10100ba
     field public static final int activityCloseExitAnimation = 16842939; // 0x10100bb
-    field public static final int activityHeight = 16844019; // 0x10104f3
+    field public static final int activityHeight = 16844021; // 0x10104f5
     field public static final int activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
-    field public static final int activityWidth = 16844018; // 0x10104f2
+    field public static final int activityWidth = 16844020; // 0x10104f4
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -878,6 +878,7 @@
     field public static final int listChoiceIndicatorSingle = 16843289; // 0x1010219
     field public static final int listDivider = 16843284; // 0x1010214
     field public static final int listDividerAlertDialog = 16843525; // 0x1010305
+    field public static final int listMenuViewStyle = 16844018; // 0x10104f2
     field public static final int listPopupWindowStyle = 16843519; // 0x10102ff
     field public static final int listPreferredItemHeight = 16842829; // 0x101004d
     field public static final int listPreferredItemHeightLarge = 16843654; // 0x1010386
@@ -1083,6 +1084,7 @@
     field public static final int resizeClip = 16843983; // 0x10104cf
     field public static final int resizeMode = 16843619; // 0x1010363
     field public static final int resizeable = 16843405; // 0x101028d
+    field public static final int resizeableActivity = 16844022; // 0x10104f6
     field public static final int resource = 16842789; // 0x1010025
     field public static final int restoreAnyVersion = 16843450; // 0x10102ba
     field public static final deprecated int restoreNeedsApplication = 16843421; // 0x101029d
@@ -1244,6 +1246,7 @@
     field public static final int strokeLineJoin = 16843788; // 0x101040c
     field public static final int strokeMiterLimit = 16843789; // 0x101040d
     field public static final int strokeWidth = 16843783; // 0x1010407
+    field public static final int subMenuArrow = 16844019; // 0x10104f3
     field public static final int submitBackground = 16843912; // 0x1010488
     field public static final int subtitle = 16843473; // 0x10102d1
     field public static final int subtitleTextAppearance = 16843823; // 0x101042f
@@ -3580,14 +3583,14 @@
     method public void setImmersive(boolean);
     method public void setIntent(android.content.Intent);
     method public final void setMediaController(android.media.session.MediaController);
-    method public final void setProgress(int);
-    method public final void setProgressBarIndeterminate(boolean);
-    method public final void setProgressBarIndeterminateVisibility(boolean);
-    method public final void setProgressBarVisibility(boolean);
+    method public final deprecated void setProgress(int);
+    method public final deprecated void setProgressBarIndeterminate(boolean);
+    method public final deprecated void setProgressBarIndeterminateVisibility(boolean);
+    method public final deprecated void setProgressBarVisibility(boolean);
     method public void setRequestedOrientation(int);
     method public final void setResult(int);
     method public final void setResult(int, android.content.Intent);
-    method public final void setSecondaryProgress(int);
+    method public final deprecated void setSecondaryProgress(int);
     method public void setTaskDescription(android.app.ActivityManager.TaskDescription);
     method public void setTitle(java.lang.CharSequence);
     method public void setTitle(int);
@@ -10000,12 +10003,14 @@
     method public int diff(android.content.res.Configuration);
     method public boolean equals(android.content.res.Configuration);
     method public int getLayoutDirection();
+    method public android.util.LocaleList getLocales();
     method public boolean isLayoutSizeAtLeast(int);
     method public boolean isScreenRound();
     method public static boolean needNewResources(int, int);
     method public void readFromParcel(android.os.Parcel);
     method public void setLayoutDirection(java.util.Locale);
     method public void setLocale(java.util.Locale);
+    method public void setLocales(android.util.LocaleList);
     method public void setTo(android.content.res.Configuration);
     method public void setToDefaults();
     method public int updateFrom(android.content.res.Configuration);
@@ -10079,7 +10084,7 @@
     field public int hardKeyboardHidden;
     field public int keyboard;
     field public int keyboardHidden;
-    field public java.util.Locale locale;
+    field public deprecated java.util.Locale locale;
     field public int mcc;
     field public int mnc;
     field public int navigation;
@@ -11923,6 +11928,7 @@
     method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
     method public void getTextBounds(char[], int, int, android.graphics.Rect);
     method public java.util.Locale getTextLocale();
+    method public android.util.LocaleList getTextLocales();
     method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
     method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
     method public float getTextScaleX();
@@ -11978,6 +11984,7 @@
     method public void setSubpixelText(boolean);
     method public void setTextAlign(android.graphics.Paint.Align);
     method public void setTextLocale(java.util.Locale);
+    method public void setTextLocales(android.util.LocaleList);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSkewX(float);
@@ -12633,6 +12640,7 @@
     method public int getIntrinsicWidth();
     method public int getLayoutDirection();
     method public final int getLevel();
+    method public final float getLevelFloat();
     method public int getMinimumHeight();
     method public int getMinimumWidth();
     method public abstract int getOpacity();
@@ -12652,6 +12660,7 @@
     method protected void onBoundsChange(android.graphics.Rect);
     method public boolean onLayoutDirectionChanged(int);
     method protected boolean onLevelChange(int);
+    method protected boolean onLevelChange(float);
     method protected boolean onStateChange(int[]);
     method public static int resolveOpacity(int, int);
     method public void scheduleSelf(java.lang.Runnable, long);
@@ -12669,12 +12678,15 @@
     method public void setHotspotBounds(int, int, int, int);
     method public final boolean setLayoutDirection(int);
     method public final boolean setLevel(int);
+    method public final boolean setLevel(float);
     method public boolean setState(int[]);
     method public void setTint(int);
     method public void setTintList(android.content.res.ColorStateList);
     method public void setTintMode(android.graphics.PorterDuff.Mode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(java.lang.Runnable);
+    field public static final int MAX_LEVEL = 10000; // 0x2710
+    field public static final float MAX_LEVEL_FLOAT = 10000.0f;
   }
 
   public static abstract interface Drawable.Callback {
@@ -19627,7 +19639,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public boolean sendObject(int, android.os.ParcelFileDescriptor);
+    method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
 
@@ -19676,6 +19688,7 @@
     method public android.mtp.MtpObjectInfo.Builder setImagePixWidth(int);
     method public android.mtp.MtpObjectInfo.Builder setKeywords(java.lang.String);
     method public android.mtp.MtpObjectInfo.Builder setName(java.lang.String);
+    method public android.mtp.MtpObjectInfo.Builder setObjectHandle(int);
     method public android.mtp.MtpObjectInfo.Builder setParent(int);
     method public android.mtp.MtpObjectInfo.Builder setProtectionStatus(int);
     method public android.mtp.MtpObjectInfo.Builder setSequenceNumber(int);
@@ -36494,11 +36507,16 @@
 
   public final class LocaleList {
     ctor public LocaleList();
+    ctor public LocaleList(java.util.Locale);
     ctor public LocaleList(java.util.Locale[]);
+    method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getDefault();
+    method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getPrimary();
     method public boolean isEmpty();
     method public int size();
+    method public java.lang.String toLanguageTags();
   }
 
   public final class Log {
@@ -37646,6 +37664,7 @@
     field public static final int KEYCODE_SLEEP = 223; // 0xdf
     field public static final int KEYCODE_SOFT_LEFT = 1; // 0x1
     field public static final int KEYCODE_SOFT_RIGHT = 2; // 0x2
+    field public static final int KEYCODE_SOFT_SLEEP = 276; // 0x114
     field public static final int KEYCODE_SPACE = 62; // 0x3e
     field public static final int KEYCODE_STAR = 17; // 0x11
     field public static final int KEYCODE_STB_INPUT = 180; // 0xb4
@@ -39655,23 +39674,23 @@
     field public static final int FEATURE_CONTENT_TRANSITIONS = 12; // 0xc
     field public static final int FEATURE_CONTEXT_MENU = 6; // 0x6
     field public static final int FEATURE_CUSTOM_TITLE = 7; // 0x7
-    field public static final int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
+    field public static final deprecated int FEATURE_INDETERMINATE_PROGRESS = 5; // 0x5
     field public static final int FEATURE_LEFT_ICON = 3; // 0x3
     field public static final int FEATURE_NO_TITLE = 1; // 0x1
     field public static final int FEATURE_OPTIONS_PANEL = 0; // 0x0
-    field public static final int FEATURE_PROGRESS = 2; // 0x2
+    field public static final deprecated int FEATURE_PROGRESS = 2; // 0x2
     field public static final int FEATURE_RIGHT_ICON = 4; // 0x4
     field public static final int FEATURE_SWIPE_TO_DISMISS = 11; // 0xb
     field public static final int ID_ANDROID_CONTENT = 16908290; // 0x1020002
     field public static final java.lang.String NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME = "android:navigation:background";
-    field public static final int PROGRESS_END = 10000; // 0x2710
-    field public static final int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
-    field public static final int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
-    field public static final int PROGRESS_SECONDARY_END = 30000; // 0x7530
-    field public static final int PROGRESS_SECONDARY_START = 20000; // 0x4e20
-    field public static final int PROGRESS_START = 0; // 0x0
-    field public static final int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
-    field public static final int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
+    field public static final deprecated int PROGRESS_END = 10000; // 0x2710
+    field public static final deprecated int PROGRESS_INDETERMINATE_OFF = -4; // 0xfffffffc
+    field public static final deprecated int PROGRESS_INDETERMINATE_ON = -3; // 0xfffffffd
+    field public static final deprecated int PROGRESS_SECONDARY_END = 30000; // 0x7530
+    field public static final deprecated int PROGRESS_SECONDARY_START = 20000; // 0x4e20
+    field public static final deprecated int PROGRESS_START = 0; // 0x0
+    field public static final deprecated int PROGRESS_VISIBILITY_OFF = -2; // 0xfffffffe
+    field public static final deprecated int PROGRESS_VISIBILITY_ON = -1; // 0xffffffff
     field public static final java.lang.String STATUS_BAR_BACKGROUND_TRANSITION_NAME = "android:status:background";
   }
 
@@ -44320,6 +44339,7 @@
     method public java.lang.CharSequence getText();
     method public final android.content.res.ColorStateList getTextColors();
     method public java.util.Locale getTextLocale();
+    method public android.util.LocaleList getTextLocales();
     method public float getTextScaleX();
     method public float getTextSize();
     method public int getTotalPaddingBottom();
@@ -44432,6 +44452,7 @@
     method public final void setTextKeepState(java.lang.CharSequence);
     method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
     method public void setTextLocale(java.util.Locale);
+    method public void setTextLocales(android.util.LocaleList);
     method public void setTextScaleX(float);
     method public void setTextSize(float);
     method public void setTextSize(int, float);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 07fa52c..73c3786 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2761,6 +2761,15 @@
     }
 
     /**
+     * Activates this activity, hence bringing it to the top and giving it focus.
+     * Note: This will only work for activities which are located on the freeform desktop.
+     * @hide
+     */
+    public void activateActivity() throws RemoteException {
+        ActivityManagerNative.getDefault().activateActivity(mToken);
+    }
+
+    /**
      * Called to process key events.  You can override this to intercept all
      * key events before they are dispatched to the window.  Be sure to call
      * this implementation for key events that should be handled normally.
@@ -5427,7 +5436,9 @@
      * via {@link #requestWindowFeature(int)}.
      *
      * @param visible Whether to show the progress bars in the title.
+     * @deprecated No longer supported starting in API 21.
      */
+    @Deprecated
     public final void setProgressBarVisibility(boolean visible) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS, visible ? Window.PROGRESS_VISIBILITY_ON :
             Window.PROGRESS_VISIBILITY_OFF);
@@ -5440,7 +5451,9 @@
      * via {@link #requestWindowFeature(int)}.
      *
      * @param visible Whether to show the progress bars in the title.
+     * @deprecated No longer supported starting in API 21.
      */
+    @Deprecated
     public final void setProgressBarIndeterminateVisibility(boolean visible) {
         getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
                 visible ? Window.PROGRESS_VISIBILITY_ON : Window.PROGRESS_VISIBILITY_OFF);
@@ -5454,7 +5467,9 @@
      * via {@link #requestWindowFeature(int)}.
      *
      * @param indeterminate Whether the horizontal progress bar should be indeterminate.
+     * @deprecated No longer supported starting in API 21.
      */
+    @Deprecated
     public final void setProgressBarIndeterminate(boolean indeterminate) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
                 indeterminate ? Window.PROGRESS_INDETERMINATE_ON
@@ -5470,7 +5485,9 @@
      * @param progress The progress for the progress bar. Valid ranges are from
      *            0 to 10000 (both inclusive). If 10000 is given, the progress
      *            bar will be completely filled and will fade out.
+     * @deprecated No longer supported starting in API 21.
      */
+    @Deprecated
     public final void setProgress(int progress) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS, progress + Window.PROGRESS_START);
     }
@@ -5487,7 +5504,9 @@
      *
      * @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from
      *            0 to 10000 (both inclusive).
+     * @deprecated No longer supported starting in API 21.
      */
+    @Deprecated
     public final void setSecondaryProgress(int secondaryProgress) {
         getWindow().setFeatureInt(Window.FEATURE_PROGRESS,
                 secondaryProgress + Window.PROGRESS_SECONDARY_START);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 580f721..eeae20f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -1108,7 +1108,7 @@
      * of {@link #RECENT_WITH_EXCLUDED} and {@link #RECENT_IGNORE_UNAVAILABLE}.
      *
      * @return Returns a list of RecentTaskInfo records describing each of
-     * the recent tasks.
+     * the recent tasks. Most recently activated tasks go first.
      *
      * @hide
      */
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index b003b31..1f1f356 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -827,10 +827,18 @@
             return true;
         }
 
+        case ACTIVATE_ACTIVITY_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            activateActivity(token);
+            reply.writeNoException();
+            return true;
+        }
+
         case SET_FOCUSED_TASK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
-            setFocusedStack(taskId);
+            setFocusedTask(taskId);
             reply.writeNoException();
             return true;
         }
@@ -3623,6 +3631,18 @@
         return focusedStackId;
     }
     @Override
+    public void activateActivity(IBinder token) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(ACTIVATE_ACTIVITY_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
     public void setFocusedTask(int taskId) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 2406985..933f98d 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IRemoteCallback;
@@ -59,6 +60,13 @@
     public static final String KEY_PACKAGE_NAME = "android:activity.packageName";
 
     /**
+     * The bounds that the activity should be started in. Set to null explicitly
+     * for full screen. If the key is not found, previous bounds will be preserved.
+     * @hide
+     */
+    public static final String KEY_BOUNDS = "android:activity.bounds";
+
+    /**
      * Type of animation that arguments specify.
      * @hide
      */
@@ -163,6 +171,8 @@
     public static final int ANIM_CLIP_REVEAL = 11;
 
     private String mPackageName;
+    private boolean mHasBounds;
+    private Rect mBounds;
     private int mAnimationType = ANIM_NONE;
     private int mCustomEnterResId;
     private int mCustomExitResId;
@@ -631,6 +641,10 @@
         } catch (RuntimeException e) {
             Slog.w(TAG, e);
         }
+        mHasBounds = opts.containsKey(KEY_BOUNDS);
+        if (mHasBounds) {
+            mBounds = opts.getParcelable(KEY_BOUNDS);
+        }
         mAnimationType = opts.getInt(KEY_ANIM_TYPE);
         switch (mAnimationType) {
             case ANIM_CUSTOM:
@@ -677,11 +691,28 @@
     }
 
     /** @hide */
+    public ActivityOptions setBounds(Rect bounds) {
+        mHasBounds = true;
+        mBounds = bounds;
+        return this;
+    }
+
+    /** @hide */
     public String getPackageName() {
         return mPackageName;
     }
 
     /** @hide */
+    public boolean hasBounds() {
+        return mHasBounds;
+    }
+
+    /** @hide */
+    public Rect getBounds(){
+        return mBounds;
+    }
+
+    /** @hide */
     public int getAnimationType() {
         return mAnimationType;
     }
@@ -867,6 +898,9 @@
         if (mPackageName != null) {
             b.putString(KEY_PACKAGE_NAME, mPackageName);
         }
+        if (mHasBounds) {
+            b.putParcelable(KEY_BOUNDS, mBounds);
+        }
         b.putInt(KEY_ANIM_TYPE, mAnimationType);
         if (mUsageTimeReport != null) {
             b.putParcelable(KEY_USAGE_TIME_REPORT, mUsageTimeReport);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 412e3cd..67dee7f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4593,27 +4593,6 @@
         }
         updateDefaultDensity();
 
-        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
-        if (!Process.isIsolated()) {
-            final File cacheDir = appContext.getCacheDir();
-
-            if (cacheDir != null) {
-                // Provide a usable directory for temporary files
-                System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
-            } else {
-                Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory");
-            }
-
-            // Use codeCacheDir to store generated/compiled graphics code
-            final File codeCacheDir = appContext.getCodeCacheDir();
-            if (codeCacheDir != null) {
-                setupGraphicsSupport(data.info, codeCacheDir);
-            } else {
-                Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
-            }
-        }
-
-
         final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
         DateFormat.set24HourTimePref(is24Hr);
 
@@ -4685,29 +4664,28 @@
         /**
          * Initialize the default http proxy in this process for the reasons we set the time zone.
          */
-        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
+        final IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
         if (b != null) {
             // In pre-boot mode (doing initial launch to collect password), not
             // all system is up.  This includes the connectivity service, so don't
             // crash if we can't get it.
-            IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
+            final IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
             try {
                 final ProxyInfo proxyInfo = service.getProxyForNetwork(null);
                 Proxy.setHttpProxySystemProperty(proxyInfo);
             } catch (RemoteException e) {}
         }
 
+        // Instrumentation info affects the class loader, so load it before
+        // setting up the app context.
+        final InstrumentationInfo ii;
         if (data.instrumentationName != null) {
-            InstrumentationInfo ii = null;
             try {
-                ii = appContext.getPackageManager().
-                    getInstrumentationInfo(data.instrumentationName, 0);
+                ii = new ApplicationPackageManager(null, getPackageManager())
+                        .getInstrumentationInfo(data.instrumentationName, 0);
             } catch (PackageManager.NameNotFoundException e) {
-            }
-            if (ii == null) {
                 throw new RuntimeException(
-                    "Unable to find instrumentation info for: "
-                    + data.instrumentationName);
+                        "Unable to find instrumentation info for: " + data.instrumentationName);
             }
 
             mInstrumentationPackageName = ii.packageName;
@@ -4717,8 +4695,33 @@
             mInstrumentedAppDir = data.info.getAppDir();
             mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
             mInstrumentedLibDir = data.info.getLibDir();
+        } else {
+            ii = null;
+        }
 
-            ApplicationInfo instrApp = new ApplicationInfo();
+        final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
+        if (!Process.isIsolated()) {
+            final File cacheDir = appContext.getCacheDir();
+            if (cacheDir != null) {
+                // Provide a usable directory for temporary files
+                System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
+            } else {
+                Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property "
+                        + "due to missing cache directory");
+            }
+
+            // Use codeCacheDir to store generated/compiled graphics code
+            final File codeCacheDir = appContext.getCodeCacheDir();
+            if (codeCacheDir != null) {
+                setupGraphicsSupport(data.info, codeCacheDir);
+            } else {
+                Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory");
+            }
+        }
+
+        // Continue loading instrumentation.
+        if (ii != null) {
+            final ApplicationInfo instrApp = new ApplicationInfo();
             instrApp.packageName = ii.packageName;
             instrApp.sourceDir = ii.sourceDir;
             instrApp.publicSourceDir = ii.publicSourceDir;
@@ -4726,12 +4729,13 @@
             instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
             instrApp.dataDir = ii.dataDir;
             instrApp.nativeLibraryDir = ii.nativeLibraryDir;
-            LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
+
+            final LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                     appContext.getClassLoader(), false, true, false);
-            ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
+            final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
 
             try {
-                java.lang.ClassLoader cl = instrContext.getClassLoader();
+                final ClassLoader cl = instrContext.getClassLoader();
                 mInstrumentation = (Instrumentation)
                     cl.loadClass(data.instrumentationName.getClassName()).newInstance();
             } catch (Exception e) {
@@ -4740,18 +4744,17 @@
                     + data.instrumentationName + ": " + e.toString(), e);
             }
 
-            mInstrumentation.init(this, instrContext, appContext,
-                   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
-                   data.instrumentationUiAutomationConnection);
+            final ComponentName component = new ComponentName(ii.packageName, ii.name);
+            mInstrumentation.init(this, instrContext, appContext, component,
+                    data.instrumentationWatcher, data.instrumentationUiAutomationConnection);
 
             if (mProfiler.profileFile != null && !ii.handleProfiling
                     && mProfiler.profileFd == null) {
                 mProfiler.handlingProfiling = true;
-                File file = new File(mProfiler.profileFile);
+                final File file = new File(mProfiler.profileFile);
                 file.getParentFile().mkdirs();
                 Debug.startMethodTracing(file.toString(), 8 * 1024 * 1024);
             }
-
         } else {
             mInstrumentation = new Instrumentation();
         }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 3b026d2..132ffef 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2196,6 +2196,7 @@
             fragment.mTag = tag;
             fragment.mInLayout = true;
             fragment.mFragmentManager = this;
+            fragment.mHost = mHost;
             fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
             addFragment(fragment, true);
         } else if (fragment.mInLayout) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d355219..47abf26 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -147,6 +147,7 @@
     public boolean isInHomeStack(int taskId) throws RemoteException;
     public void setFocusedStack(int stackId) throws RemoteException;
     public int getFocusedStackId() throws RemoteException;
+    public void activateActivity(IBinder token) throws RemoteException;
     public void setFocusedTask(int taskId) throws RemoteException;
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException;
     public int getTaskForActivity(IBinder token, boolean onlyRoot) throws RemoteException;
@@ -892,4 +893,5 @@
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
     int GET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
     int SET_ACTIVITY_BOUNDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
+    int ACTIVATE_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 348;
 }
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 1605b3e..3187984 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -154,6 +154,7 @@
      * @param displayId display Id.
      * @param overrideConfiguration override configurations.
      * @param compatInfo the compatibility info. Must not be null.
+     * @param classLoader the class loader for the resource package
      */
     Resources getTopLevelResources(String resDir, String[] splitResDirs,
             String[] overlayDirs, String[] libDirs, int displayId,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e3414d9..7ffac0a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -213,7 +213,8 @@
 
      * @see DeviceAdminReceiver
      * @deprecated Use {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME}. This extra is still
-     * supported.
+     * supported, but only if there is only one device admin receiver in the package that requires
+     * the permission {@link android.Manifest.permission#BIND_DEVICE_ADMIN}.
      */
     @Deprecated
     public static final String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 6feb860..914945b 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -531,12 +531,14 @@
 
     /**
      * String retrieved from the seinfo tag found in selinux policy. This value
-     * is useful in setting an SELinux security context on the process as well
-     * as its data directory.
+     * can be overridden with a value set through the mac_permissions.xml policy
+     * construct. This value is useful in setting an SELinux security context on
+     * the process as well as its data directory. The String default is being used
+     * here to represent a catchall label when no policy matches.
      *
      * {@hide}
      */
-    public String seinfo;
+    public String seinfo = "default";
 
     /**
      * Paths to all shared libraries this application is linked against.  This
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 2aae1de..7392563 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -77,7 +77,7 @@
     public static final int FLAG_DISABLED = 0x00000040;
 
 
-    public static final int NO_PROFILE_GROUP_ID = -1;
+    public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;
 
     public int id;
     public int serialNumber;
@@ -87,6 +87,7 @@
     public long creationTime;
     public long lastLoggedInTime;
     public int profileGroupId;
+    public int restrictedProfileParentId;
 
     /** User is only partially created. */
     public boolean partial;
@@ -102,6 +103,7 @@
         this.flags = flags;
         this.iconPath = iconPath;
         this.profileGroupId = NO_PROFILE_GROUP_ID;
+        this.restrictedProfileParentId = NO_PROFILE_GROUP_ID;
     }
 
     public boolean isPrimary() {
@@ -206,6 +208,7 @@
         dest.writeInt(partial ? 1 : 0);
         dest.writeInt(profileGroupId);
         dest.writeInt(guestToRemove ? 1 : 0);
+        dest.writeInt(restrictedProfileParentId);
     }
 
     public static final Parcelable.Creator<UserInfo> CREATOR
@@ -229,5 +232,6 @@
         partial = source.readInt() != 0;
         profileGroupId = source.readInt();
         guestToRemove = source.readInt() != 0;
+        restrictedProfileParentId = source.readInt();
     }
 }
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index fd60476..927c02f 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -22,11 +22,13 @@
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.Nullable;
 import android.content.pm.ActivityInfo;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
+import android.util.LocaleList;
 import android.view.View;
 
 import java.io.IOException;
@@ -36,7 +38,7 @@
 /**
  * This class describes all device configuration information that can
  * impact the resources the application retrieves.  This includes both
- * user-specified configuration options (locale and scaling) as well
+ * user-specified configuration options (locale list and scaling) as well
  * as device configurations (such as input modes, screen size and screen orientation).
  * <p>You can acquire this object from {@link Resources}, using {@link
  * Resources#getConfiguration}. Thus, from an activity, you can get it by chaining the request
@@ -78,8 +80,13 @@
      * Current user preference for the locale, corresponding to
      * <a href="{@docRoot}guide/topics/resources/providing-resources.html#LocaleQualifier">locale</a>
      * resource qualifier.
+     *
+     * @deprecated Do not set or read this directly. Use {@link #getLocales()} and
+     * {@link #setLocales(LocaleList)}.
      */
-    public Locale locale;
+    @Deprecated public Locale locale;
+
+    private LocaleList mLocaleList;
 
     /**
      * Locale should persist on setting.  This is hidden because it is really
@@ -648,6 +655,15 @@
         setTo(o);
     }
 
+    /* This brings mLocaleList in sync with locale in case a user of the older API who doesn't know
+     * about setLocales() has changed locale directly. */
+    private void fixUpLocaleList() {
+        if ((locale == null && !mLocaleList.isEmpty()) ||
+                (locale != null && !locale.equals(mLocaleList.getPrimary()))) {
+            mLocaleList = new LocaleList(locale);
+        }
+    }
+
     public void setTo(Configuration o) {
         fontScale = o.fontScale;
         mcc = o.mcc;
@@ -655,6 +671,8 @@
         if (o.locale != null) {
             locale = (Locale) o.locale.clone();
         }
+        o.fixUpLocaleList();
+        mLocaleList = o.mLocaleList;
         userSetLocale = o.userSetLocale;
         touchscreen = o.touchscreen;
         keyboard = o.keyboard;
@@ -692,11 +710,12 @@
         } else {
             sb.append("?mnc");
         }
-        if (locale != null) {
+        fixUpLocaleList();
+        if (!mLocaleList.isEmpty()) {
             sb.append(" ");
-            sb.append(locale);
+            sb.append(mLocaleList);
         } else {
-            sb.append(" ?locale");
+            sb.append(" ?localeList");
         }
         int layoutDir = (screenLayout&SCREENLAYOUT_LAYOUTDIR_MASK);
         switch (layoutDir) {
@@ -819,6 +838,7 @@
     public void setToDefaults() {
         fontScale = 1;
         mcc = mnc = 0;
+        mLocaleList = LocaleList.getEmptyLocaleList();
         locale = null;
         userSetLocale = false;
         touchscreen = TOUCHSCREEN_UNDEFINED;
@@ -864,16 +884,20 @@
             changed |= ActivityInfo.CONFIG_MNC;
             mnc = delta.mnc;
         }
-        if (delta.locale != null
-                && (locale == null || !locale.equals(delta.locale))) {
+        fixUpLocaleList();
+        delta.fixUpLocaleList();
+        if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
             changed |= ActivityInfo.CONFIG_LOCALE;
-            locale = delta.locale != null
-                    ? (Locale) delta.locale.clone() : null;
-            // If locale has changed, then layout direction is also changed ...
-            changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
-            // ... and we need to update the layout direction (represented by the first
-            // 2 most significant bits in screenLayout).
-            setLayoutDirection(locale);
+            mLocaleList = delta.mLocaleList;
+            // delta.locale can't be null, since delta.mLocaleList is not empty.
+            if (!delta.locale.equals(locale)) {
+                locale = (Locale) delta.locale.clone();
+                // If locale has changed, then layout direction is also changed ...
+                changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+                // ... and we need to update the layout direction (represented by the first
+                // 2 most significant bits in screenLayout).
+                setLayoutDirection(locale);
+            }
         }
         final int deltaScreenLayoutDir = delta.screenLayout & SCREENLAYOUT_LAYOUTDIR_MASK;
         if (deltaScreenLayoutDir != SCREENLAYOUT_LAYOUTDIR_UNDEFINED &&
@@ -1023,8 +1047,9 @@
         if (delta.mnc != 0 && mnc != delta.mnc) {
             changed |= ActivityInfo.CONFIG_MNC;
         }
-        if (delta.locale != null
-                && (locale == null || !locale.equals(delta.locale))) {
+        fixUpLocaleList();
+        delta.fixUpLocaleList();
+        if (!delta.mLocaleList.isEmpty() && !mLocaleList.equals(delta.mLocaleList)) {
             changed |= ActivityInfo.CONFIG_LOCALE;
             changed |= ActivityInfo.CONFIG_LAYOUT_DIRECTION;
         }
@@ -1146,14 +1171,15 @@
         dest.writeFloat(fontScale);
         dest.writeInt(mcc);
         dest.writeInt(mnc);
-        if (locale == null) {
-            dest.writeInt(0);
-        } else {
-            dest.writeInt(1);
-            dest.writeString(locale.getLanguage());
-            dest.writeString(locale.getCountry());
-            dest.writeString(locale.getVariant());
+
+        fixUpLocaleList();
+        final int localeListSize = mLocaleList.size();
+        dest.writeInt(localeListSize);
+        for (int i = 0; i < localeListSize; ++i) {
+            final Locale l = mLocaleList.get(i);
+            dest.writeString(l.toLanguageTag());
         }
+
         if(userSetLocale) {
             dest.writeInt(1);
         } else {
@@ -1182,10 +1208,15 @@
         fontScale = source.readFloat();
         mcc = source.readInt();
         mnc = source.readInt();
-        if (source.readInt() != 0) {
-            locale = new Locale(source.readString(), source.readString(),
-                    source.readString());
+
+        final int localeListSize = source.readInt();
+        final Locale[] localeArray = new Locale[localeListSize];
+        for (int i = 0; i < localeListSize; ++i) {
+            localeArray[i] = Locale.forLanguageTag(source.readString());
         }
+        mLocaleList = new LocaleList(localeArray);
+        locale = mLocaleList.getPrimary();
+
         userSetLocale = (source.readInt()==1);
         touchscreen = source.readInt();
         keyboard = source.readInt();
@@ -1234,18 +1265,33 @@
         if (n != 0) return n;
         n = this.mnc - that.mnc;
         if (n != 0) return n;
-        if (this.locale == null) {
-            if (that.locale != null) return 1;
-        } else if (that.locale == null) {
+
+        fixUpLocaleList();
+        that.fixUpLocaleList();
+        // for backward compatibility, we consider an empty locale list to be greater
+        // than any non-empty locale list.
+        if (this.mLocaleList.isEmpty()) {
+            if (!that.mLocaleList.isEmpty()) return 1;
+        } else if (that.mLocaleList.isEmpty()) {
             return -1;
         } else {
-            n = this.locale.getLanguage().compareTo(that.locale.getLanguage());
-            if (n != 0) return n;
-            n = this.locale.getCountry().compareTo(that.locale.getCountry());
-            if (n != 0) return n;
-            n = this.locale.getVariant().compareTo(that.locale.getVariant());
+            final int minSize = Math.min(this.mLocaleList.size(), that.mLocaleList.size());
+            for (int i = 0; i < minSize; ++i) {
+                final Locale thisLocale = this.mLocaleList.get(i);
+                final Locale thatLocale = that.mLocaleList.get(i);
+                n = thisLocale.getLanguage().compareTo(thatLocale.getLanguage());
+                if (n != 0) return n;
+                n = thisLocale.getCountry().compareTo(thatLocale.getCountry());
+                if (n != 0) return n;
+                n = thisLocale.getVariant().compareTo(thatLocale.getVariant());
+                if (n != 0) return n;
+                n = thisLocale.toLanguageTag().compareTo(thatLocale.toLanguageTag());
+                if (n != 0) return n;
+            }
+            n = this.mLocaleList.size() - that.mLocaleList.size();
             if (n != 0) return n;
         }
+
         n = this.touchscreen - that.touchscreen;
         if (n != 0) return n;
         n = this.keyboard - that.keyboard;
@@ -1288,13 +1334,13 @@
         }
         return false;
     }
-    
+
     public int hashCode() {
         int result = 17;
         result = 31 * result + Float.floatToIntBits(fontScale);
         result = 31 * result + mcc;
         result = 31 * result + mnc;
-        result = 31 * result + (locale != null ? locale.hashCode() : 0);
+        result = 31 * result + mLocaleList.hashCode();
         result = 31 * result + touchscreen;
         result = 31 * result + keyboard;
         result = 31 * result + keyboardHidden;
@@ -1312,14 +1358,47 @@
     }
 
     /**
-     * Set the locale. This is the preferred way for setting up the locale (instead of using the
-     * direct accessor). This will also set the layout direction according to the locale.
+     * Get the locale list. This is the preferred way for getting the locales (instead of using
+     * the direct accessor to {@link #locale}, which would only provide the primary locale).
+     *
+     * @return The locale list.
+     */
+    public LocaleList getLocales() {
+        fixUpLocaleList();
+        return mLocaleList;
+    }
+
+    /**
+     * Set the locale list. This is the preferred way for setting up the locales (instead of using
+     * the direct accessor or {@link #setLocale(Locale)}). This will also set the layout direction
+     * according to the first locale in the list.
+     *
+     * Note that the layout direction will always come from the first locale in the locale list,
+     * even if the locale is not supported by the resources (the resources may only support
+     * another locale further down the list which has a different direction).
+     *
+     * @param locales The locale list. If null, an empty LocaleList will be assigned.
+     */
+    public void setLocales(@Nullable LocaleList locales) {
+        mLocaleList = locales == null ? LocaleList.getEmptyLocaleList() : locales;
+        locale = mLocaleList.getPrimary();
+        setLayoutDirection(locale);
+    }
+
+    /**
+     * Set the locale list to a list of just one locale. This will also set the layout direction
+     * according to the locale.
+     *
+     * Note that after this is run, calling <code>.equals()</code> on the input locale and the
+     * {@link #locale} attribute would return <code>true</code> if they are not null, but there is
+     * no guarantee that they would be the same object.
+     *
+     * See also the note about layout direction in {@link #setLocales(LocaleList)}.
      *
      * @param loc The locale. Can be null.
      */
-    public void setLocale(Locale loc) {
-        locale = loc;
-        setLayoutDirection(locale);
+    public void setLocale(@Nullable Locale loc) {
+        setLocales(new LocaleList(loc));
     }
 
     /**
@@ -1335,19 +1414,19 @@
     }
 
     /**
-     * Set the layout direction from the Locale.
+     * Set the layout direction from a Locale.
      *
-     * @param locale The Locale. If null will set the layout direction to
+     * @param loc The Locale. If null will set the layout direction to
      * {@link View#LAYOUT_DIRECTION_LTR}. If not null will set it to the layout direction
      * corresponding to the Locale.
      *
      * @see View#LAYOUT_DIRECTION_LTR
      * @see View#LAYOUT_DIRECTION_RTL
      */
-    public void setLayoutDirection(Locale locale) {
+    public void setLayoutDirection(Locale loc) {
         // There is a "1" difference between the configuration values for
         // layout direction and View constants for layout direction, just add "1".
-        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(locale);
+        final int layoutDirection = 1 + TextUtils.getLayoutDirectionFromLocale(loc);
         screenLayout = (screenLayout&~SCREENLAYOUT_LAYOUTDIR_MASK)|
                 (layoutDirection << SCREENLAYOUT_LAYOUTDIR_SHIFT);
     }
@@ -1370,21 +1449,21 @@
      *
      * @hide
      */
-    public static String localeToResourceQualifier(Locale locale) {
+    public static String localeToResourceQualifier(Locale loc) {
         StringBuilder sb = new StringBuilder();
-        boolean l = (locale.getLanguage().length() != 0);
-        boolean c = (locale.getCountry().length() != 0);
-        boolean s = (locale.getScript().length() != 0);
-        boolean v = (locale.getVariant().length() != 0);
-
+        boolean l = (loc.getLanguage().length() != 0);
+        boolean c = (loc.getCountry().length() != 0);
+        boolean s = (loc.getScript().length() != 0);
+        boolean v = (loc.getVariant().length() != 0);
+        // TODO: take script and extensions into account
         if (l) {
-            sb.append(locale.getLanguage());
+            sb.append(loc.getLanguage());
             if (c) {
-                sb.append("-r").append(locale.getCountry());
+                sb.append("-r").append(loc.getCountry());
                 if (s) {
-                    sb.append("-s").append(locale.getScript());
+                    sb.append("-s").append(loc.getScript());
                     if (v) {
-                        sb.append("-v").append(locale.getVariant());
+                        sb.append("-v").append(loc.getVariant());
                     }
                 }
             }
@@ -1409,6 +1488,7 @@
             }
         }
 
+        // TODO: send the whole locale list
         if (config.locale != null && !config.locale.getLanguage().isEmpty()) {
             parts.add(localeToResourceQualifier(config.locale));
         }
@@ -1646,8 +1726,10 @@
             delta.mnc = change.mnc;
         }
 
-        if ((base.locale == null && change.locale != null) ||
-                (base.locale != null && !base.locale.equals(change.locale)))  {
+        base.fixUpLocaleList();
+        change.fixUpLocaleList();
+        if (!base.mLocaleList.equals(change.mLocaleList))  {
+            delta.mLocaleList = change.mLocaleList;
             delta.locale = change.locale;
         }
 
@@ -1724,7 +1806,7 @@
     private static final String XML_ATTR_FONT_SCALE = "fs";
     private static final String XML_ATTR_MCC = "mcc";
     private static final String XML_ATTR_MNC = "mnc";
-    private static final String XML_ATTR_LOCALE = "locale";
+    private static final String XML_ATTR_LOCALES = "locales";
     private static final String XML_ATTR_TOUCHSCREEN = "touch";
     private static final String XML_ATTR_KEYBOARD = "key";
     private static final String XML_ATTR_KEYBOARD_HIDDEN = "keyHid";
@@ -1754,10 +1836,9 @@
         configOut.mcc = XmlUtils.readIntAttribute(parser, XML_ATTR_MCC, 0);
         configOut.mnc = XmlUtils.readIntAttribute(parser, XML_ATTR_MNC, 0);
 
-        final String localeStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALE);
-        if (localeStr != null) {
-            configOut.locale = Locale.forLanguageTag(localeStr);
-        }
+        final String localesStr = XmlUtils.readStringAttribute(parser, XML_ATTR_LOCALES);
+        configOut.mLocaleList = LocaleList.forLanguageTags(localesStr);
+        configOut.locale = configOut.mLocaleList.getPrimary();
 
         configOut.touchscreen = XmlUtils.readIntAttribute(parser, XML_ATTR_TOUCHSCREEN,
                 TOUCHSCREEN_UNDEFINED);
@@ -1807,8 +1888,9 @@
         if (config.mnc != 0) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_MNC, config.mnc);
         }
-        if (config.locale != null) {
-            XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALE, config.locale.toLanguageTag());
+        config.fixUpLocaleList();
+        if (!config.mLocaleList.isEmpty()) {
+           XmlUtils.writeStringAttribute(xml, XML_ATTR_LOCALES, config.mLocaleList.toLanguageTags());
         }
         if (config.touchscreen != TOUCHSCREEN_UNDEFINED) {
             XmlUtils.writeIntAttribute(xml, XML_ATTR_TOUCHSCREEN, config.touchscreen);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7cff11b..1f23c0a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -392,6 +392,18 @@
     };
 
     /**
+     * @hide
+     */
+    public static abstract class LockoutResetCallback {
+
+        /**
+         * Called when lockout period expired and clients are allowed to listen for fingerprint
+         * again.
+         */
+        public void onLockoutReset() { }
+    };
+
+    /**
      * Request authentication of a crypto object. This call warms up the fingerprint hardware
      * and starts scanning for a fingerprint. It terminates when
      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
@@ -680,10 +692,37 @@
             try {
                 mService.resetTimeout(token);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+                Log.v(TAG, "Remote exception in resetTimeout(): ", e);
             }
         } else {
-            Log.w(TAG, "getAuthenticatorId(): Service not connected!");
+            Log.w(TAG, "resetTimeout(): Service not connected!");
+        }
+    }
+
+    /**
+     * @hide
+     */
+    public void addLockoutResetCallback(final LockoutResetCallback callback) {
+        if (mService != null) {
+            try {
+                mService.addLockoutResetCallback(
+                        new IFingerprintServiceLockoutResetCallback.Stub() {
+
+                    @Override
+                    public void onLockoutReset(long deviceId) throws RemoteException {
+                        mHandler.post(new Runnable() {
+                            @Override
+                            public void run() {
+                                callback.onLockoutReset();
+                            }
+                        });
+                    }
+                });
+            } catch (RemoteException e) {
+                Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+            }
+        } else {
+            Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
         }
     }
 
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3356354..690a751 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -17,6 +17,7 @@
 
 import android.os.Bundle;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.hardware.fingerprint.Fingerprint;
 import java.util.List;
 
@@ -71,4 +72,7 @@
 
     // Reset the timeout when user authenticates with strong auth (e.g. PIN, pattern or password)
     void resetTimeout(in byte [] cryptoToken);
+
+    // Add a callback which gets notified when the fingerprint lockout period expired.
+    void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
new file mode 100644
index 0000000..c9a5d59
--- /dev/null
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl
@@ -0,0 +1,28 @@
+/*
+ * 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.hardware.fingerprint;
+
+import android.hardware.fingerprint.Fingerprint;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+/**
+ * Callback when lockout period expired and clients are allowed to authenticate again.
+ * @hide
+ */
+oneway interface IFingerprintServiceLockoutResetCallback {
+    void onLockoutReset(long deviceId);
+}
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index 465d142..c8b45c7 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -19,6 +19,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.IInputDevicesChangedListener;
+import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.TouchCalibration;
 import android.os.IBinder;
 import android.view.InputDevice;
@@ -60,6 +61,9 @@
     // Registers an input devices changed listener.
     void registerInputDevicesChangedListener(IInputDevicesChangedListener listener);
 
+    // Registers a tablet mode change listener
+    void registerTabletModeChangedListener(ITabletModeChangedListener listener);
+
     // Input device vibrator control.
     void vibrate(int deviceId, in long[] pattern, int repeat, IBinder token);
     void cancelVibrate(int deviceId, IBinder token);
diff --git a/core/java/android/hardware/input/ITabletModeChangedListener.aidl b/core/java/android/hardware/input/ITabletModeChangedListener.aidl
new file mode 100644
index 0000000..a8559a7
--- /dev/null
+++ b/core/java/android/hardware/input/ITabletModeChangedListener.aidl
@@ -0,0 +1,23 @@
+/*
+ * 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.hardware.input;
+
+/** @hide */
+interface ITabletModeChangedListener {
+    /* Called when the device enters or exits tablet mode. */
+    oneway void onTabletModeChanged(long whenNanos, boolean inTabletMode);
+}
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 444f020..bae5757 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,6 +16,7 @@
 
 package android.hardware.input;
 
+import com.android.internal.os.SomeArgs;
 import com.android.internal.util.ArrayUtils;
 
 import android.annotation.SdkConstant;
@@ -29,6 +30,7 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
@@ -38,6 +40,7 @@
 import android.view.InputEvent;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Provides information about input devices and available key layouts.
@@ -67,6 +70,11 @@
     private final ArrayList<InputDeviceListenerDelegate> mInputDeviceListeners =
             new ArrayList<InputDeviceListenerDelegate>();
 
+    // Guarded by mTabletModeLock
+    private final Object mTabletModeLock = new Object();
+    private TabletModeChangedListener mTabletModeChangedListener;
+    private List<OnTabletModeChangedListenerDelegate> mOnTabletModeChangedListeners;
+
     /**
      * Broadcast Action: Query available keyboard layouts.
      * <p>
@@ -291,6 +299,7 @@
         }
 
         synchronized (mInputDevicesLock) {
+            populateInputDevicesLocked();
             int index = findInputDeviceListenerLocked(listener);
             if (index < 0) {
                 mInputDeviceListeners.add(new InputDeviceListenerDelegate(listener, handler));
@@ -331,6 +340,72 @@
     }
 
     /**
+     * Register a tablet mode changed listener.
+     *
+     * @param listener The listener to register.
+     * @param handler The handler on which the listener should be invoked, or null
+     * if the listener should be invoked on the calling thread's looper.
+     * @hide
+     */
+    public void registerOnTabletModeChangedListener(
+            OnTabletModeChangedListener listener, Handler handler) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+        synchronized (mTabletModeLock) {
+            if (mOnTabletModeChangedListeners == null) {
+                initializeTabletModeListenerLocked();
+            }
+            int idx = findOnTabletModeChangedListenerLocked(listener);
+            if (idx < 0) {
+                OnTabletModeChangedListenerDelegate d =
+                    new OnTabletModeChangedListenerDelegate(listener, handler);
+                mOnTabletModeChangedListeners.add(d);
+            }
+        }
+    }
+
+    /**
+     * Unregister a tablet mode changed listener.
+     *
+     * @param listener The listener to unregister.
+     * @hide
+     */
+    public void unregisterOnTabletModeChangedListener(OnTabletModeChangedListener listener) {
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+        synchronized (mTabletModeLock) {
+            int idx = findOnTabletModeChangedListenerLocked(listener);
+            if (idx >= 0) {
+                OnTabletModeChangedListenerDelegate d = mOnTabletModeChangedListeners.remove(idx);
+                d.removeCallbacksAndMessages(null);
+            }
+        }
+    }
+
+    private void initializeTabletModeListenerLocked() {
+        final TabletModeChangedListener listener = new TabletModeChangedListener();
+        try {
+            mIm.registerTabletModeChangedListener(listener);
+        } catch (RemoteException ex) {
+            throw new RuntimeException("Could not register tablet mode changed listener", ex);
+        }
+        mTabletModeChangedListener = listener;
+        mOnTabletModeChangedListeners = new ArrayList<>();
+    }
+
+    private int findOnTabletModeChangedListenerLocked(OnTabletModeChangedListener listener) {
+        final int N = mOnTabletModeChangedListeners.size();
+        for (int i = 0; i < N; i++) {
+            if (mOnTabletModeChangedListeners.get(i).mListener == listener) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
      * Gets information about all supported keyboard layouts.
      * <p>
      * The input manager consults the built-in keyboard layouts as well
@@ -769,6 +844,22 @@
         return false;
     }
 
+
+    private void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
+        if (DEBUG) {
+            Log.d(TAG, "Received tablet mode changed: "
+                    + "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode);
+        }
+        synchronized (mTabletModeLock) {
+            final int N = mOnTabletModeChangedListeners.size();
+            for (int i = 0; i < N; i++) {
+                OnTabletModeChangedListenerDelegate listener =
+                        mOnTabletModeChangedListeners.get(i);
+                listener.sendTabletModeChanged(whenNanos, inTabletMode);
+            }
+        }
+    }
+
     /**
      * Gets a vibrator service associated with an input device, assuming it has one.
      * @return The vibrator, never null.
@@ -838,6 +929,57 @@
         }
     }
 
+    /** @hide */
+    public interface OnTabletModeChangedListener {
+        /**
+         * Called whenever the device goes into or comes out of tablet mode.
+         *
+         * @param whenNanos The time at which the device transitioned into or
+         * out of tablet mode. This is given in nanoseconds in the
+         * {@link SystemClock#uptimeMillis} time base.
+         */
+        void onTabletModeChanged(long whenNanos, boolean inTabletMode);
+    }
+
+    private final class TabletModeChangedListener extends ITabletModeChangedListener.Stub {
+        @Override
+        public void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
+            InputManager.this.onTabletModeChanged(whenNanos, inTabletMode);
+        }
+    }
+
+    private static final class OnTabletModeChangedListenerDelegate extends Handler {
+        private static final int MSG_TABLET_MODE_CHANGED = 0;
+
+        public final OnTabletModeChangedListener mListener;
+
+        public OnTabletModeChangedListenerDelegate(
+                OnTabletModeChangedListener listener, Handler handler) {
+            super(handler != null ? handler.getLooper() : Looper.myLooper());
+            mListener = listener;
+        }
+
+        public void sendTabletModeChanged(long whenNanos, boolean inTabletMode) {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
+            args.argi2 = (int) (whenNanos >> 32);
+            args.arg1 = (Boolean) inTabletMode;
+            obtainMessage(MSG_TABLET_MODE_CHANGED, args).sendToTarget();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_TABLET_MODE_CHANGED:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
+                    boolean inTabletMode = (boolean) args.arg1;
+                    mListener.onTabletModeChanged(whenNanos, inTabletMode);
+                    break;
+            }
+        }
+    }
+
     private final class InputDeviceVibrator extends Vibrator {
         private final int mDeviceId;
         private final Binder mToken;
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a4e6219..d4e6c82 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -100,6 +100,16 @@
     public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
 
     /**
+     * A temporary hack until SUPL system can get off the legacy APIS.
+     * They do too many network requests and the long list of apps listening
+     * and waking due to the CONNECTIVITY_ACTION bcast makes it expensive.
+     * Use this bcast intent instead for SUPL requests.
+     * @hide
+     */
+    public static final String CONNECTIVITY_ACTION_SUPL =
+            "android.net.conn.CONNECTIVITY_CHANGE_SUPL";
+
+    /**
      * The device has connected to a network that has presented a captive
      * portal, which is blocking Internet connectivity. The user was presented
      * with a notification that network sign in is required,
@@ -1038,11 +1048,13 @@
             type = "enableDUN";
             result = TYPE_MOBILE_DUN;
         } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) {
-            type = "enableSUPL";
+           type = "enableSUPL";
             result = TYPE_MOBILE_SUPL;
-        } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
-            type = "enableMMS";
-            result = TYPE_MOBILE_MMS;
+        // back out this hack for mms as they no longer need this and it's causing
+        // device slowdowns - b/23350688 (note, supl still needs this)
+        //} else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) {
+        //    type = "enableMMS";
+        //    result = TYPE_MOBILE_MMS;
         } else if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
             type = "enableHIPRI";
             result = TYPE_MOBILE_HIPRI;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 80169a9..bad94fc 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -169,7 +169,7 @@
     /**
      * Current version of checkin data format.
      */
-    static final String CHECKIN_VERSION = "14";
+    static final String CHECKIN_VERSION = "15";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -468,6 +468,7 @@
          * @param which one of STATS_SINCE_CHARGED, STATS_SINCE_UNPLUGGED, or STATS_CURRENT.
          * @see BatteryStats#getCpuSpeedSteps()
          */
+        @Deprecated
         public abstract long getTimeAtCpuSpeed(int step, int which);
 
         public static abstract class Sensor {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index e742f98..70cff00 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -108,6 +108,12 @@
     public abstract void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis);
 
     /**
+     * Used by the window manager to tell the power manager that the user is no longer actively
+     * using the device.
+     */
+    public abstract void setUserInactiveOverrideFromWindowManager();
+
+    /**
      * Used by device administration to set the maximum screen off timeout.
      *
      * This method must only be called by the device administration policy manager.
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 4da88ee..7529c52 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -77,6 +77,8 @@
     public static final long TRACE_TAG_POWER = 1L << 17;
     /** @hide */
     public static final long TRACE_TAG_PACKAGE_MANAGER = 1L << 18;
+    /** @hide */
+    public static final long TRACE_TAG_SYSTEM_SERVER = 1L << 19;
 
     private static final long TRACE_TAG_NOT_READY = 1L << 63;
     private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 849f5de..64e2505 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -927,6 +927,28 @@
     }
 
     /**
+     * Creates a restricted profile with the specified name.
+     *
+     * @param name profile's name
+     * @return UserInfo object for the created user, or null if the user could not be created.
+     * @hide
+     */
+    public UserInfo createRestrictedProfile(String name) {
+        try {
+            if (isSplitSystemUser()) {
+                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
+                        UserHandle.getCallingUserId());
+            } else {
+                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
+                        UserHandle.USER_SYSTEM);
+            }
+        } catch (RemoteException e) {
+            Log.w(TAG, "Could not create a restricted profile", e);
+        }
+        return null;
+    }
+
+    /**
      * @hide
      * Marks the guest user for deletion to allow a new guest to be created before deleting
      * the current user who is a guest.
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index cf937e1..f9387b3 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1115,13 +1115,18 @@
      */
     public int getOffsetForHorizontal(int line, float horiz) {
         // TODO: use Paint.getOffsetForAdvance to avoid binary search
-        int max = getLineEnd(line) - 1;
-        int min = getLineStart(line);
+        final int lineEndOffset = getLineEnd(line);
+        final int max;
+        if (line == getLineCount() - 1) {
+            max = lineEndOffset;
+        } else {
+            max = mPaint.getTextRunCursor(mText, 0, mText.length(),
+                    isRtlCharAt(lineEndOffset) ? Paint.DIRECTION_RTL : Paint.DIRECTION_LTR,
+                    lineEndOffset, Paint.CURSOR_BEFORE);
+        }
+        final int min = getLineStart(line);
         Directions dirs = getLineDirections(line);
 
-        if (line == getLineCount() - 1)
-            max++;
-
         int best = min;
         float bestdist = Math.abs(getPrimaryHorizontal(best) - horiz);
 
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 017735a..379651e 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -16,15 +16,19 @@
 
 package android.util;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
+
+import com.android.internal.annotations.GuardedBy;
 
 import java.util.HashSet;
 import java.util.Locale;
 
 // TODO: We don't except too many LocaleLists to exist at the same time, and
 // we need access to the data at native level, so we should pass the data
-// down to the native level, create a mapt of every list seen there, take a
-// pointer back, and just keep that pointed in the Java-level object, so
+// down to the native level, create a map of every list seen there, take a
+// pointer back, and just keep that pointer in the Java-level object, so
 // things could be copied very quickly.
 
 /**
@@ -34,6 +38,7 @@
 public final class LocaleList {
     private final Locale[] mList;
     private static final Locale[] sEmptyList = new Locale[0];
+    private static final LocaleList sEmptyLocaleList = new LocaleList();
 
     public Locale get(int location) {
         return location < mList.length ? mList[location] : null;
@@ -51,6 +56,60 @@
         return mList.length;
     }
 
+    @Override
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+        if (!(other instanceof LocaleList))
+            return false;
+        final Locale[] otherList = ((LocaleList) other).mList;
+        if (mList.length != otherList.length)
+            return false;
+        for (int i = 0; i < mList.length; ++i) {
+            if (!mList[i].equals(otherList[i]))
+                return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 1;
+        for (int i = 0; i < mList.length; ++i) {
+            result = 31 * result + mList[i].hashCode();
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("[");
+        for (int i = 0; i < mList.length; ++i) {
+            sb.append(mList[i]);
+            if (i < mList.length - 1) {
+                sb.append(',');
+            }
+        }
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public String toLanguageTags() {
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < mList.length; ++i) {
+            sb.append(mList[i].toLanguageTag());
+            if (i < mList.length - 1) {
+                sb.append(',');
+            }
+        }
+        return sb.toString();
+    }
+
+    /**
+     * It is almost always better to call {@link #getEmptyLocaleList()} instead which returns
+     * a pre-constructed empty locale list.
+     */
     public LocaleList() {
         mList = sEmptyList;
     }
@@ -59,6 +118,19 @@
      * @throws NullPointerException if any of the input locales is <code>null</code>.
      * @throws IllegalArgumentException if any of the input locales repeat.
      */
+    public LocaleList(@Nullable Locale locale) {
+        if (locale == null) {
+            mList = sEmptyList;
+        } else {
+            mList = new Locale[1];
+            mList[0] = (Locale) locale.clone();
+        }
+    }
+
+    /**
+     * @throws NullPointerException if any of the input locales is <code>null</code>.
+     * @throws IllegalArgumentException if any of the input locales repeat.
+     */
     public LocaleList(@Nullable Locale[] list) {
         if (list == null || list.length == 0) {
             mList = sEmptyList;
@@ -79,4 +151,39 @@
             mList = localeList;
         }
     }
+
+    public static LocaleList getEmptyLocaleList() {
+        return sEmptyLocaleList;
+    }
+
+    public static LocaleList forLanguageTags(@Nullable String list) {
+        if (list == null || list.equals("")) {
+            return getEmptyLocaleList();
+        } else {
+            final String[] tags = list.split(",");
+            final Locale[] localeArray = new Locale[tags.length];
+            for (int i = 0; i < localeArray.length; ++i) {
+                localeArray[i] = Locale.forLanguageTag(tags[i]);
+            }
+            return new LocaleList(localeArray);
+        }
+    }
+
+    private final static Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static LocaleList sDefaultLocaleList;
+
+    // TODO: fix this to return the default system locale list once we have that
+    @NonNull @Size(min=1)
+    public static LocaleList getDefault() {
+        Locale defaultLocale = Locale.getDefault();
+        synchronized (sLock) {
+            if (sDefaultLocaleList == null || sDefaultLocaleList.size() != 1
+                    || !defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
+                sDefaultLocaleList = new LocaleList(defaultLocale);
+            }
+        }
+        return sDefaultLocaleList;
+    }
 }
diff --git a/core/java/android/view/HandlerActionQueue.java b/core/java/android/view/HandlerActionQueue.java
new file mode 100644
index 0000000..4758a34
--- /dev/null
+++ b/core/java/android/view/HandlerActionQueue.java
@@ -0,0 +1,127 @@
+/*
+ * 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 com.android.internal.util.GrowingArrayUtils;
+
+import android.os.Handler;
+
+import java.util.ArrayList;
+
+/**
+ * Class used to enqueue pending work from Views when no Handler is attached.
+ *
+ * @hide Exposed for test framework only.
+ */
+public class HandlerActionQueue {
+    private HandlerAction[] mActions;
+    private int mCount;
+
+    public void post(Runnable action) {
+        postDelayed(action, 0);
+    }
+
+    public void postDelayed(Runnable action, long delayMillis) {
+        final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
+
+        synchronized (this) {
+            if (mActions == null) {
+                mActions = new HandlerAction[4];
+            }
+            mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
+            mCount++;
+        }
+    }
+
+    public void removeCallbacks(Runnable action) {
+        synchronized (this) {
+            final int count = mCount;
+            int j = 0;
+
+            final HandlerAction[] actions = mActions;
+            for (int i = 0; i < count; i++) {
+                if (actions[i].matches(action)) {
+                    // Remove this action by overwriting it within
+                    // this loop or nulling it out later.
+                    continue;
+                }
+
+                if (j != i) {
+                    // At least one previous entry was removed, so
+                    // this one needs to move to the "new" list.
+                    actions[j] = actions[i];
+                }
+
+                j++;
+            }
+
+            // The "new" list only has j entries.
+            mCount = j;
+
+            // Null out any remaining entries.
+            for (; j < count; j++) {
+                actions[j] = null;
+            }
+        }
+    }
+
+    public void executeActions(Handler handler) {
+        synchronized (this) {
+            final HandlerAction[] actions = mActions;
+            for (int i = 0, count = mCount; i < count; i++) {
+                final HandlerAction handlerAction = actions[i];
+                handler.postDelayed(handlerAction.action, handlerAction.delay);
+            }
+
+            mActions = null;
+            mCount = 0;
+        }
+    }
+
+    public int size() {
+        return mCount;
+    }
+
+    public Runnable getRunnable(int index) {
+        if (index >= mCount) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mActions[index].action;
+    }
+
+    public long getDelay(int index) {
+        if (index >= mCount) {
+            throw new IndexOutOfBoundsException();
+        }
+        return mActions[index].delay;
+    }
+
+    private static class HandlerAction {
+        final Runnable action;
+        final long delay;
+
+        public HandlerAction(Runnable action, long delay) {
+            this.action = action;
+            this.delay = delay;
+        }
+
+        public boolean matches(Runnable otherAction) {
+            return otherAction == null && action == null
+                    || action != null && action.equals(otherAction);
+        }
+    }
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index f86adfe..33c51ff 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -97,21 +97,21 @@
      * @param launchTaskBehind True if the token is been launched from behind.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param configuration Configuration that is being used with this task.
      */
-    Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds);
+            in Rect taskBounds, in Configuration configuration);
     /**
      *
      * @param token The token we are adding to the input task Id.
      * @param taskId The Id of the task we are adding the token to.
      * @param taskBounds Bounds to use when creating a new Task with the input task Id if
      *                   the task doesn't exist yet.
-     * @return The configuration of the task if it was newly created. null otherwise.
+     * @param config Configuration that is being used with this task.
      */
-    Configuration setAppTask(IBinder token, int taskId, in Rect taskBounds);
+    void setAppTask(IBinder token, int taskId, in Rect taskBounds, in Configuration config);
     void setAppOrientation(IApplicationToken token, int requestedOrientation);
     int getAppOrientation(IApplicationToken token);
     void setFocusedApp(IBinder token, boolean moveFocusNow);
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 6d89824..1c20cab 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -788,8 +788,10 @@
     /** Key code constant: Step backward media key.
      * Steps media backward, one frame at a time. */
     public static final int KEYCODE_MEDIA_STEP_BACKWARD = 275;
+    /** Key code constant: put device to sleep unless a wakelock is held. */
+    public static final int KEYCODE_SOFT_SLEEP = 276;
 
-    private static final int LAST_KEYCODE = KEYCODE_MEDIA_STEP_BACKWARD;
+    private static final int LAST_KEYCODE = KEYCODE_SOFT_SLEEP;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 5970c3f..bcf9b2c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -484,6 +484,7 @@
         public boolean secure;
         public long appVsyncOffsetNanos;
         public long presentationDeadlineNanos;
+        public int colorTransform;
 
         public PhysicalDisplayInfo() {
         }
@@ -507,7 +508,8 @@
                     && yDpi == other.yDpi
                     && secure == other.secure
                     && appVsyncOffsetNanos == other.appVsyncOffsetNanos
-                    && presentationDeadlineNanos == other.presentationDeadlineNanos;
+                    && presentationDeadlineNanos == other.presentationDeadlineNanos
+                    && colorTransform == other.colorTransform;
         }
 
         @Override
@@ -525,6 +527,7 @@
             secure = other.secure;
             appVsyncOffsetNanos = other.appVsyncOffsetNanos;
             presentationDeadlineNanos = other.presentationDeadlineNanos;
+            colorTransform = other.colorTransform;
         }
 
         // For debugging purposes
@@ -533,7 +536,8 @@
             return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
                     + "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
                     + ", appVsyncOffset " + appVsyncOffsetNanos
-                    + ", bufferDeadline " + presentationDeadlineNanos + "}";
+                    + ", bufferDeadline " + presentationDeadlineNanos
+                    + ", colorTransform " + colorTransform + "}";
         }
     }
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index f6119e2..420f7a1 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -407,6 +407,10 @@
         nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
     }
 
+    public void serializeDisplayListTree() {
+        nSerializeDisplayListTree(mNativeProxy);
+    }
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -532,6 +536,8 @@
     private static native void nStopDrawing(long nativeProxy);
     private static native void nNotifyFramePending(long nativeProxy);
 
+    private static native void nSerializeDisplayListTree(long nativeProxy);
+
     private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
             @DumpFlags int dumpFlags);
     private static native void nDumpProfileData(byte[] data, FileDescriptor fd);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 16d9bf3..ed48319 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3823,6 +3823,12 @@
     private static SparseArray<String> mAttributeMap;
 
     /**
+     * Queue of pending runnables. Used to postpone calls to post() until this
+     * view is attached and has a handler.
+     */
+    private HandlerActionQueue mRunQueue;
+
+    /**
      * @hide
      */
     String mStartActivityRequestWho;
@@ -6681,14 +6687,15 @@
     }
 
     /**
-     * Gets the {@link View} description. It briefly describes the view and is
-     * primarily used for accessibility support. Set this property to enable
-     * better accessibility support for your application. This is especially
-     * true for views that do not have textual representation (For example,
-     * ImageButton).
+     * Returns the {@link View}'s content description.
+     * <p>
+     * <strong>Note:</strong> Do not override this method, as it will have no
+     * effect on the content description presented to accessibility services.
+     * You must call {@link #setContentDescription(CharSequence)} to modify the
+     * content description.
      *
-     * @return The content description.
-     *
+     * @return the content description
+     * @see #setContentDescription(CharSequence)
      * @attr ref android.R.styleable#View_contentDescription
      */
     @ViewDebug.ExportedProperty(category = "accessibility")
@@ -6697,14 +6704,19 @@
     }
 
     /**
-     * Sets the {@link View} description. It briefly describes the view and is
-     * primarily used for accessibility support. Set this property to enable
-     * better accessibility support for your application. This is especially
-     * true for views that do not have textual representation (For example,
-     * ImageButton).
+     * Sets the {@link View}'s content description.
+     * <p>
+     * A content description briefly describes the view and is primarily used
+     * for accessibility support to determine how a view should be presented to
+     * the user. In the case of a view with no textual representation, such as
+     * {@link android.widget.ImageButton}, a useful content description
+     * explains what the view does. For example, an image button with a phone
+     * icon that is used to place a call may use "Call" as its content
+     * description. An image of a floppy disk that is used to save a file may
+     * use "Save".
      *
      * @param contentDescription The content description.
-     *
+     * @see #getContentDescription()
      * @attr ref android.R.styleable#View_contentDescription
      */
     @RemotableViewMethod
@@ -13010,6 +13022,18 @@
     }
 
     /**
+     * Returns the queue of runnable for this view.
+     *
+     * @return the queue of runnables for this view
+     */
+    private HandlerActionQueue getRunQueue() {
+        if (mRunQueue == null) {
+            mRunQueue = new HandlerActionQueue();
+        }
+        return mRunQueue;
+    }
+
+    /**
      * Gets the view root associated with the View.
      * @return The view root, or null if none.
      * @hide
@@ -13046,8 +13070,10 @@
         if (attachInfo != null) {
             return attachInfo.mHandler.post(action);
         }
-        // Assume that post will succeed later
-        ViewRootImpl.getRunQueue().post(action);
+
+        // Postpone the runnable until we know on which thread it needs to run.
+        // Assume that the runnable will be successfully placed after attach.
+        getRunQueue().post(action);
         return true;
     }
 
@@ -13075,8 +13101,10 @@
         if (attachInfo != null) {
             return attachInfo.mHandler.postDelayed(action, delayMillis);
         }
-        // Assume that post will succeed later
-        ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+
+        // Postpone the runnable until we know on which thread it needs to run.
+        // Assume that the runnable will be successfully placed after attach.
+        getRunQueue().postDelayed(action, delayMillis);
         return true;
     }
 
@@ -13095,8 +13123,9 @@
             attachInfo.mViewRootImpl.mChoreographer.postCallback(
                     Choreographer.CALLBACK_ANIMATION, action, null);
         } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().post(action);
+            // Postpone the runnable until we know
+            // on which thread it needs to run.
+            getRunQueue().post(action);
         }
     }
 
@@ -13118,8 +13147,9 @@
             attachInfo.mViewRootImpl.mChoreographer.postCallbackDelayed(
                     Choreographer.CALLBACK_ANIMATION, action, null, delayMillis);
         } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+            // Postpone the runnable until we know
+            // on which thread it needs to run.
+            getRunQueue().postDelayed(action, delayMillis);
         }
     }
 
@@ -13146,8 +13176,7 @@
                 attachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
                         Choreographer.CALLBACK_ANIMATION, action, null);
             }
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().removeCallbacks(action);
+            getRunQueue().removeCallbacks(action);
         }
         return true;
     }
@@ -14565,7 +14594,6 @@
      *        this view
      */
     void dispatchAttachedToWindow(AttachInfo info, int visibility) {
-        //System.out.println("Attached! " + this);
         mAttachInfo = info;
         if (mOverlay != null) {
             mOverlay.getOverlayView().dispatchAttachedToWindow(info, visibility);
@@ -14581,6 +14609,11 @@
             mAttachInfo.mScrollContainers.add(this);
             mPrivateFlags |= PFLAG_SCROLL_CONTAINER_ADDED;
         }
+        // Transfer all pending runnables.
+        if (mRunQueue != null) {
+            mRunQueue.executeActions(info.mHandler);
+            mRunQueue = null;
+        }
         performCollectViewAttributes(mAttachInfo, visibility);
         onAttachedToWindow();
 
@@ -16866,7 +16899,9 @@
                         Choreographer.CALLBACK_ANIMATION, what, who,
                         Choreographer.subtractFrameDelay(delay));
             } else {
-                ViewRootImpl.getRunQueue().postDelayed(what, delay);
+                // Postpone the runnable until we know
+                // on which thread it needs to run.
+                getRunQueue().postDelayed(what, delay);
             }
         }
     }
@@ -16884,7 +16919,7 @@
                 mAttachInfo.mViewRootImpl.mChoreographer.removeCallbacks(
                         Choreographer.CALLBACK_ANIMATION, what, who);
             }
-            ViewRootImpl.getRunQueue().removeCallbacks(what);
+            getRunQueue().removeCallbacks(what);
         }
     }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index aa20dfb..d26e914 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -28,7 +28,6 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -131,7 +130,7 @@
      */
     static final int MAX_TRACKBALL_DELAY = 250;
 
-    static final ThreadLocal<RunQueue> sRunQueues = new ThreadLocal<RunQueue>();
+    static final ThreadLocal<HandlerActionQueue> sRunQueues = new ThreadLocal<HandlerActionQueue>();
 
     static final ArrayList<Runnable> sFirstDrawHandlers = new ArrayList<Runnable>();
     static boolean sFirstDrawComplete = false;
@@ -2276,6 +2275,9 @@
      */
     void outputDisplayList(View view) {
         view.mRenderNode.output();
+        if (mAttachInfo.mHardwareRenderer != null) {
+            ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
+        }
     }
 
     /**
@@ -6519,6 +6521,19 @@
         return false;
     }
 
+    /**
+     * Force the window to report its next draw.
+     * <p>
+     * This method is only supposed to be used to speed up the interaction from SystemUI and window
+     * manager when waiting for the first frame to be drawn when turning on the screen. DO NOT USE
+     * unless you fully understand this interaction.
+     * @hide
+     */
+    public void setReportNextDraw() {
+        mReportNextDraw = true;
+        invalidate();
+    }
+
     void changeCanvasOpacity(boolean opaque) {
         Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque);
         if (mAttachInfo.mHardwareRenderer != null) {
@@ -6743,90 +6758,17 @@
         }
     }
 
-    static RunQueue getRunQueue() {
-        RunQueue rq = sRunQueues.get();
+    static HandlerActionQueue getRunQueue() {
+        HandlerActionQueue rq = sRunQueues.get();
         if (rq != null) {
             return rq;
         }
-        rq = new RunQueue();
+        rq = new HandlerActionQueue();
         sRunQueues.set(rq);
         return rq;
     }
 
     /**
-     * The run queue is used to enqueue pending work from Views when no Handler is
-     * attached.  The work is executed during the next call to performTraversals on
-     * the thread.
-     * @hide
-     */
-    static final class RunQueue {
-        private final ArrayList<HandlerAction> mActions = new ArrayList<HandlerAction>();
-
-        void post(Runnable action) {
-            postDelayed(action, 0);
-        }
-
-        void postDelayed(Runnable action, long delayMillis) {
-            HandlerAction handlerAction = new HandlerAction();
-            handlerAction.action = action;
-            handlerAction.delay = delayMillis;
-
-            synchronized (mActions) {
-                mActions.add(handlerAction);
-            }
-        }
-
-        void removeCallbacks(Runnable action) {
-            final HandlerAction handlerAction = new HandlerAction();
-            handlerAction.action = action;
-
-            synchronized (mActions) {
-                final ArrayList<HandlerAction> actions = mActions;
-
-                while (actions.remove(handlerAction)) {
-                    // Keep going
-                }
-            }
-        }
-
-        void executeActions(Handler handler) {
-            synchronized (mActions) {
-                final ArrayList<HandlerAction> actions = mActions;
-                final int count = actions.size();
-
-                for (int i = 0; i < count; i++) {
-                    final HandlerAction handlerAction = actions.get(i);
-                    handler.postDelayed(handlerAction.action, handlerAction.delay);
-                }
-
-                actions.clear();
-            }
-        }
-
-        private static class HandlerAction {
-            Runnable action;
-            long delay;
-
-            @Override
-            public boolean equals(Object o) {
-                if (this == o) return true;
-                if (o == null || getClass() != o.getClass()) return false;
-
-                HandlerAction that = (HandlerAction) o;
-                return !(action != null ? !action.equals(that.action) : that.action != null);
-
-            }
-
-            @Override
-            public int hashCode() {
-                int result = action != null ? action.hashCode() : 0;
-                result = 31 * result + (int) (delay ^ (delay >>> 32));
-                return result;
-            }
-        }
-    }
-
-    /**
      * Class for managing the accessibility interaction connection
      * based on the global accessibility state.
      */
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 1a9fb34..5893f4a 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -58,14 +58,28 @@
     /** Flag for the "no title" feature, turning off the title at the top
      *  of the screen. */
     public static final int FEATURE_NO_TITLE = 1;
-    /** Flag for the progress indicator feature */
+
+    /**
+     * Flag for the progress indicator feature.
+     *
+     * @deprecated No longer supported starting in API 21.
+     */
+    @Deprecated
     public static final int FEATURE_PROGRESS = 2;
+
     /** Flag for having an icon on the left side of the title bar */
     public static final int FEATURE_LEFT_ICON = 3;
     /** Flag for having an icon on the right side of the title bar */
     public static final int FEATURE_RIGHT_ICON = 4;
-    /** Flag for indeterminate progress */
+
+    /**
+     * Flag for indeterminate progress.
+     *
+     * @deprecated No longer supported starting in API 21.
+     */
+    @Deprecated
     public static final int FEATURE_INDETERMINATE_PROGRESS = 5;
+
     /** Flag for the context menu.  This is enabled by default. */
     public static final int FEATURE_CONTEXT_MENU = 6;
     /** Flag for custom title. You cannot combine this feature with other title features. */
@@ -133,21 +147,76 @@
      */
     public static final int FEATURE_MAX = FEATURE_ACTIVITY_TRANSITIONS;
 
-    /** Flag for setting the progress bar's visibility to VISIBLE */
+    /**
+     * Flag for setting the progress bar's visibility to VISIBLE.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_VISIBILITY_ON = -1;
-    /** Flag for setting the progress bar's visibility to GONE */
+
+    /**
+     * Flag for setting the progress bar's visibility to GONE.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_VISIBILITY_OFF = -2;
-    /** Flag for setting the progress bar's indeterminate mode on */
+
+    /**
+     * Flag for setting the progress bar's indeterminate mode on.
+     *
+     * @deprecated {@link #FEATURE_INDETERMINATE_PROGRESS} and related methods
+     *             are no longer supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_INDETERMINATE_ON = -3;
-    /** Flag for setting the progress bar's indeterminate mode off */
+
+    /**
+     * Flag for setting the progress bar's indeterminate mode off.
+     *
+     * @deprecated {@link #FEATURE_INDETERMINATE_PROGRESS} and related methods
+     *             are no longer supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_INDETERMINATE_OFF = -4;
-    /** Starting value for the (primary) progress */
+
+    /**
+     * Starting value for the (primary) progress.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_START = 0;
-    /** Ending value for the (primary) progress */
+
+    /**
+     * Ending value for the (primary) progress.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_END = 10000;
-    /** Lowest possible value for the secondary progress */
+
+    /**
+     * Lowest possible value for the secondary progress.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_SECONDARY_START = 20000;
-    /** Highest possible value for the secondary progress */
+
+    /**
+     * Highest possible value for the secondary progress.
+     *
+     * @deprecated {@link #FEATURE_PROGRESS} and related methods are no longer
+     *             supported starting in API 21.
+     */
+    @Deprecated
     public static final int PROGRESS_SECONDARY_END = 30000;
 
     /**
@@ -510,6 +579,11 @@
          * @param newBounds The new target bounds of the activity in task or stack.
          */
         void setActivityBounds(Rect newBounds) throws RemoteException;
+
+        /**
+         * Activates this activity, hence bringing it to the top and giving it focus.
+         */
+        void activateActivity() throws RemoteException;
     }
 
     public Window(Context context) {
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index e77b862..72971e8 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -199,10 +199,7 @@
                 } else {
                     userId = UserHandle.myUserId();
                 }
-                IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-                IAccessibilityManager service = iBinder == null
-                        ? null : IAccessibilityManager.Stub.asInterface(iBinder);
-                sInstance = new AccessibilityManager(context, service, userId);
+                sInstance = new AccessibilityManager(context, null, userId);
             }
         }
         return sInstance;
@@ -219,10 +216,9 @@
      */
     public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
         mHandler = new MyHandler(context.getMainLooper());
-        mService = service;
         mUserId = userId;
         synchronized (mLock) {
-            tryConnectToServiceLocked();
+            tryConnectToServiceLocked(service);
         }
     }
 
@@ -612,17 +608,20 @@
 
     private  IAccessibilityManager getServiceLocked() {
         if (mService == null) {
-            tryConnectToServiceLocked();
+            tryConnectToServiceLocked(null);
         }
         return mService;
     }
 
-    private void tryConnectToServiceLocked() {
-        IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
-        if (iBinder == null) {
-            return;
+    private void tryConnectToServiceLocked(IAccessibilityManager service) {
+        if (service == null) {
+            IBinder iBinder = ServiceManager.getService(Context.ACCESSIBILITY_SERVICE);
+            if (iBinder == null) {
+                return;
+            }
+            service = IAccessibilityManager.Stub.asInterface(iBinder);
         }
-        IAccessibilityManager service = IAccessibilityManager.Stub.asInterface(iBinder);
+
         try {
             final int stateFlags = service.addClient(mClient, mUserId);
             setStateLocked(stateFlags);
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index a5696ee..64c4103 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -37,7 +37,6 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.ListPopupWindow.ForwardingListener;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.ActionMenuItemView;
 import com.android.internal.view.menu.BaseMenuPresenter;
@@ -45,6 +44,7 @@
 import com.android.internal.view.menu.MenuItemImpl;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuView;
+import com.android.internal.view.menu.ShowableListMenu;
 import com.android.internal.view.menu.SubMenuBuilder;
 
 import java.util.ArrayList;
@@ -828,7 +828,7 @@
 
             setOnTouchListener(new ForwardingListener(this) {
                 @Override
-                public ListPopupWindow getPopup() {
+                public ShowableListMenu getPopup() {
                     if (mOverflowPopup == null) {
                         return null;
                     }
@@ -1003,7 +1003,7 @@
 
     private class ActionMenuPopupCallback extends ActionMenuItemView.PopupCallback {
         @Override
-        public ListPopupWindow getPopup() {
+        public ShowableListMenu getPopup() {
             return mActionButtonPopup != null ? mActionButtonPopup.getPopup() : null;
         }
     }
diff --git a/core/java/android/widget/ActivityChooserView.java b/core/java/android/widget/ActivityChooserView.java
index f34ad71..f5c46db 100644
--- a/core/java/android/widget/ActivityChooserView.java
+++ b/core/java/android/widget/ActivityChooserView.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
 
 import android.annotation.StringRes;
 import android.content.Context;
@@ -37,7 +38,6 @@
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ActivityChooserModel.ActivityChooserModelClient;
-import android.widget.ListPopupWindow.ForwardingListener;
 
 /**
  * This class is a view for choosing an activity for handling a given {@link Intent}.
@@ -263,7 +263,7 @@
         });
         expandButton.setOnTouchListener(new ForwardingListener(expandButton) {
             @Override
-            public ListPopupWindow getPopup() {
+            public ShowableListMenu getPopup() {
                 return getListPopupWindow();
             }
 
diff --git a/core/java/android/widget/DropDownListView.java b/core/java/android/widget/DropDownListView.java
new file mode 100644
index 0000000..5536513
--- /dev/null
+++ b/core/java/android/widget/DropDownListView.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+
+import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.IntProperty;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.accessibility.AccessibilityManager;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.widget.TextView;
+import android.widget.ListView;
+
+
+/**
+ * Wrapper class for a ListView. This wrapper can hijack the focus to
+ * make sure the list uses the appropriate drawables and states when
+ * displayed on screen within a drop down. The focus is never actually
+ * passed to the drop down in this mode; the list only looks focused.
+ *
+ * @hide
+ */
+public class DropDownListView extends ListView {
+    /** Duration in milliseconds of the drag-to-open click animation. */
+    private static final long CLICK_ANIM_DURATION = 150;
+
+    /** Target alpha value for drag-to-open click animation. */
+    private static final int CLICK_ANIM_ALPHA = 0x80;
+
+    /** Wrapper around Drawable's <code>alpha</code> property. */
+    private static final IntProperty<Drawable> DRAWABLE_ALPHA =
+            new IntProperty<Drawable>("alpha") {
+                @Override
+                public void setValue(Drawable object, int value) {
+                    object.setAlpha(value);
+                }
+
+                @Override
+                public Integer get(Drawable object) {
+                    return object.getAlpha();
+                }
+            };
+
+    /*
+     * WARNING: This is a workaround for a touch mode issue.
+     *
+     * Touch mode is propagated lazily to windows. This causes problems in
+     * the following scenario:
+     * - Type something in the AutoCompleteTextView and get some results
+     * - Move down with the d-pad to select an item in the list
+     * - Move up with the d-pad until the selection disappears
+     * - Type more text in the AutoCompleteTextView *using the soft keyboard*
+     *   and get new results; you are now in touch mode
+     * - The selection comes back on the first item in the list, even though
+     *   the list is supposed to be in touch mode
+     *
+     * Using the soft keyboard triggers the touch mode change but that change
+     * is propagated to our window only after the first list layout, therefore
+     * after the list attempts to resurrect the selection.
+     *
+     * The trick to work around this issue is to pretend the list is in touch
+     * mode when we know that the selection should not appear, that is when
+     * we know the user moved the selection away from the list.
+     *
+     * This boolean is set to true whenever we explicitly hide the list's
+     * selection and reset to false whenever we know the user moved the
+     * selection back to the list.
+     *
+     * When this boolean is true, isInTouchMode() returns true, otherwise it
+     * returns super.isInTouchMode().
+     */
+    private boolean mListSelectionHidden;
+
+    /**
+     * True if this wrapper should fake focus.
+     */
+    private boolean mHijackFocus;
+
+    /** Whether to force drawing of the pressed state selector. */
+    private boolean mDrawsInPressedState;
+
+    /** Current drag-to-open click animation, if any. */
+    private Animator mClickAnimation;
+
+    /** Helper for drag-to-open auto scrolling. */
+    private AbsListViewAutoScroller mScrollHelper;
+
+    /**
+     * Creates a new list view wrapper.
+     *
+     * @param context this view's context
+     */
+    public DropDownListView(Context context, boolean hijackFocus) {
+        this(context, hijackFocus, com.android.internal.R.attr.dropDownListViewStyle);
+    }
+
+    /**
+     * Creates a new list view wrapper.
+     *
+     * @param context this view's context
+     */
+    public DropDownListView(Context context, boolean hijackFocus, int defStyleAttr) {
+        super(context, null, defStyleAttr);
+        mHijackFocus = hijackFocus;
+        // TODO: Add an API to control this
+        setCacheColorHint(0); // Transparent, since the background drawable could be anything.
+    }
+
+    /**
+     * Handles forwarded events.
+     *
+     * @param activePointerId id of the pointer that activated forwarding
+     * @return whether the event was handled
+     */
+    public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
+        boolean handledEvent = true;
+        boolean clearPressedItem = false;
+
+        final int actionMasked = event.getActionMasked();
+        switch (actionMasked) {
+            case MotionEvent.ACTION_CANCEL:
+                handledEvent = false;
+                break;
+            case MotionEvent.ACTION_UP:
+                handledEvent = false;
+                // $FALL-THROUGH$
+            case MotionEvent.ACTION_MOVE:
+                final int activeIndex = event.findPointerIndex(activePointerId);
+                if (activeIndex < 0) {
+                    handledEvent = false;
+                    break;
+                }
+
+                final int x = (int) event.getX(activeIndex);
+                final int y = (int) event.getY(activeIndex);
+                final int position = pointToPosition(x, y);
+                if (position == INVALID_POSITION) {
+                    clearPressedItem = true;
+                    break;
+                }
+
+                final View child = getChildAt(position - getFirstVisiblePosition());
+                setPressedItem(child, position, x, y);
+                handledEvent = true;
+
+                if (actionMasked == MotionEvent.ACTION_UP) {
+                    clickPressedItem(child, position);
+                }
+                break;
+        }
+
+        // Failure to handle the event cancels forwarding.
+        if (!handledEvent || clearPressedItem) {
+            clearPressedItem();
+        }
+
+        // Manage automatic scrolling.
+        if (handledEvent) {
+            if (mScrollHelper == null) {
+                mScrollHelper = new AbsListViewAutoScroller(this);
+            }
+            mScrollHelper.setEnabled(true);
+            mScrollHelper.onTouch(this, event);
+        } else if (mScrollHelper != null) {
+            mScrollHelper.setEnabled(false);
+        }
+
+        return handledEvent;
+    }
+
+    /**
+     * Sets whether the list selection is hidden, as part of a workaround for a touch mode issue
+     * (see the declaration for mListSelectionHidden).
+     * @param listSelectionHidden
+     */
+    public void setListSelectionHidden(boolean listSelectionHidden) {
+        this.mListSelectionHidden = listSelectionHidden;
+    }
+
+    /**
+     * Starts an alpha animation on the selector. When the animation ends,
+     * the list performs a click on the item.
+     */
+    private void clickPressedItem(final View child, final int position) {
+        final long id = getItemIdAtPosition(position);
+        final Animator anim = ObjectAnimator.ofInt(
+                mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
+        anim.setDuration(CLICK_ANIM_DURATION);
+        anim.setInterpolator(new AccelerateDecelerateInterpolator());
+        anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+            public void onAnimationEnd(Animator animation) {
+                performItemClick(child, position, id);
+            }
+        });
+        anim.start();
+
+        if (mClickAnimation != null) {
+            mClickAnimation.cancel();
+        }
+        mClickAnimation = anim;
+    }
+
+    private void clearPressedItem() {
+        mDrawsInPressedState = false;
+        setPressed(false);
+        updateSelectorState();
+
+        final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+        if (motionView != null) {
+            motionView.setPressed(false);
+        }
+
+        if (mClickAnimation != null) {
+            mClickAnimation.cancel();
+            mClickAnimation = null;
+        }
+    }
+
+    private void setPressedItem(View child, int position, float x, float y) {
+        mDrawsInPressedState = true;
+
+        // Ordering is essential. First, update the container's pressed state.
+        drawableHotspotChanged(x, y);
+        if (!isPressed()) {
+            setPressed(true);
+        }
+
+        // Next, run layout if we need to stabilize child positions.
+        if (mDataChanged) {
+            layoutChildren();
+        }
+
+        // Manage the pressed view based on motion position. This allows us to
+        // play nicely with actual touch and scroll events.
+        final View motionView = getChildAt(mMotionPosition - mFirstPosition);
+        if (motionView != null && motionView != child && motionView.isPressed()) {
+            motionView.setPressed(false);
+        }
+        mMotionPosition = position;
+
+        // Offset for child coordinates.
+        final float childX = x - child.getLeft();
+        final float childY = y - child.getTop();
+        child.drawableHotspotChanged(childX, childY);
+        if (!child.isPressed()) {
+            child.setPressed(true);
+        }
+
+        // Ensure that keyboard focus starts from the last touched position.
+        setSelectedPositionInt(position);
+        positionSelectorLikeTouch(position, child, x, y);
+
+        // Refresh the drawable state to reflect the new pressed state,
+        // which will also update the selector state.
+        refreshDrawableState();
+
+        if (mClickAnimation != null) {
+            mClickAnimation.cancel();
+            mClickAnimation = null;
+        }
+    }
+
+    @Override
+    boolean touchModeDrawsInPressedState() {
+        return mDrawsInPressedState || super.touchModeDrawsInPressedState();
+    }
+
+    /**
+     * Avoids jarring scrolling effect by ensuring that list elements
+     * made of a text view fit on a single line.
+     *
+     * @param position the item index in the list to get a view for
+     * @return the view for the specified item
+     */
+    @Override
+    View obtainView(int position, boolean[] isScrap) {
+        View view = super.obtainView(position, isScrap);
+
+        if (view instanceof TextView) {
+            ((TextView) view).setHorizontallyScrolling(true);
+        }
+
+        return view;
+    }
+
+    @Override
+    public boolean isInTouchMode() {
+        // WARNING: Please read the comment where mListSelectionHidden is declared
+        return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
+    }
+
+    /**
+     * Returns the focus state in the drop down.
+     *
+     * @return true always if hijacking focus
+     */
+    @Override
+    public boolean hasWindowFocus() {
+        return mHijackFocus || super.hasWindowFocus();
+    }
+
+    /**
+     * Returns the focus state in the drop down.
+     *
+     * @return true always if hijacking focus
+     */
+    @Override
+    public boolean isFocused() {
+        return mHijackFocus || super.isFocused();
+    }
+
+    /**
+     * Returns the focus state in the drop down.
+     *
+     * @return true always if hijacking focus
+     */
+    @Override
+    public boolean hasFocus() {
+        return mHijackFocus || super.hasFocus();
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/widget/ForwardingListener.java b/core/java/android/widget/ForwardingListener.java
new file mode 100644
index 0000000..7ddeff9
--- /dev/null
+++ b/core/java/android/widget/ForwardingListener.java
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewParent;
+
+import com.android.internal.view.menu.ShowableListMenu;
+
+/**
+ * Abstract class that forwards touch events to a {@link ShowableListMenu}.
+ *
+ * @hide
+ */
+public abstract class ForwardingListener
+        implements View.OnTouchListener, View.OnAttachStateChangeListener {
+
+    /** Scaled touch slop, used for detecting movement outside bounds. */
+    private final float mScaledTouchSlop;
+
+    /** Timeout before disallowing intercept on the source's parent. */
+    private final int mTapTimeout;
+
+    /** Timeout before accepting a long-press to start forwarding. */
+    private final int mLongPressTimeout;
+
+    /** Source view from which events are forwarded. */
+    private final View mSrc;
+
+    /** Runnable used to prevent conflicts with scrolling parents. */
+    private Runnable mDisallowIntercept;
+
+    /** Runnable used to trigger forwarding on long-press. */
+    private Runnable mTriggerLongPress;
+
+    /** Whether this listener is currently forwarding touch events. */
+    private boolean mForwarding;
+
+    /**
+     * Whether forwarding was initiated by a long-press. If so, we won't
+     * force the window to dismiss when the touch stream ends.
+     */
+    private boolean mWasLongPress;
+
+    /** The id of the first pointer down in the current event stream. */
+    private int mActivePointerId;
+
+    public ForwardingListener(View src) {
+        mSrc = src;
+        mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
+        mTapTimeout = ViewConfiguration.getTapTimeout();
+
+        // Use a medium-press timeout. Halfway between tap and long-press.
+        mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
+
+        src.addOnAttachStateChangeListener(this);
+    }
+
+    /**
+     * Returns the popup to which this listener is forwarding events.
+     * <p>
+     * Override this to return the correct popup. If the popup is displayed
+     * asynchronously, you may also need to override
+     * {@link #onForwardingStopped} to prevent premature cancellation of
+     * forwarding.
+     *
+     * @return the popup to which this listener is forwarding events
+     */
+    public abstract ShowableListMenu getPopup();
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        final boolean wasForwarding = mForwarding;
+        final boolean forwarding;
+        if (wasForwarding) {
+            forwarding = onTouchForwarded(event) || !onForwardingStopped();
+        } else {
+            forwarding = onTouchObserved(event) && onForwardingStarted();
+
+            if (forwarding) {
+                // Make sure we cancel any ongoing source event stream.
+                final long now = SystemClock.uptimeMillis();
+                final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
+                        0.0f, 0.0f, 0);
+                mSrc.onTouchEvent(e);
+                e.recycle();
+            }
+        }
+
+        mForwarding = forwarding;
+        return forwarding || wasForwarding;
+    }
+
+    @Override
+    public void onViewAttachedToWindow(View v) {
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        mForwarding = false;
+        mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+
+        if (mDisallowIntercept != null) {
+            mSrc.removeCallbacks(mDisallowIntercept);
+        }
+    }
+
+    /**
+     * Called when forwarding would like to start.
+     * <p>
+     * By default, this will show the popup returned by {@link #getPopup()}.
+     * It may be overridden to perform another action, like clicking the
+     * source view or preparing the popup before showing it.
+     *
+     * @return true to start forwarding, false otherwise
+     */
+    protected boolean onForwardingStarted() {
+        final ShowableListMenu popup = getPopup();
+        if (popup != null && !popup.isShowing()) {
+            popup.show();
+        }
+        return true;
+    }
+
+    /**
+     * Called when forwarding would like to stop.
+     * <p>
+     * By default, this will dismiss the popup returned by
+     * {@link #getPopup()}. It may be overridden to perform some other
+     * action.
+     *
+     * @return true to stop forwarding, false otherwise
+     */
+    protected boolean onForwardingStopped() {
+        final ShowableListMenu popup = getPopup();
+        if (popup != null && popup.isShowing()) {
+            popup.dismiss();
+        }
+        return true;
+    }
+
+    /**
+     * Observes motion events and determines when to start forwarding.
+     *
+     * @param srcEvent motion event in source view coordinates
+     * @return true to start forwarding motion events, false otherwise
+     */
+    private boolean onTouchObserved(MotionEvent srcEvent) {
+        final View src = mSrc;
+        if (!src.isEnabled()) {
+            return false;
+        }
+
+        final int actionMasked = srcEvent.getActionMasked();
+        switch (actionMasked) {
+            case MotionEvent.ACTION_DOWN:
+                mActivePointerId = srcEvent.getPointerId(0);
+                mWasLongPress = false;
+
+                if (mDisallowIntercept == null) {
+                    mDisallowIntercept = new DisallowIntercept();
+                }
+                src.postDelayed(mDisallowIntercept, mTapTimeout);
+
+                if (mTriggerLongPress == null) {
+                    mTriggerLongPress = new TriggerLongPress();
+                }
+                src.postDelayed(mTriggerLongPress, mLongPressTimeout);
+                break;
+            case MotionEvent.ACTION_MOVE:
+                final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
+                if (activePointerIndex >= 0) {
+                    final float x = srcEvent.getX(activePointerIndex);
+                    final float y = srcEvent.getY(activePointerIndex);
+
+                    // Has the pointer moved outside of the view?
+                    if (!src.pointInView(x, y, mScaledTouchSlop)) {
+                        clearCallbacks();
+
+                        // Don't let the parent intercept our events.
+                        src.getParent().requestDisallowInterceptTouchEvent(true);
+                        return true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+            case MotionEvent.ACTION_UP:
+                clearCallbacks();
+                break;
+        }
+
+        return false;
+    }
+
+    private void clearCallbacks() {
+        if (mTriggerLongPress != null) {
+            mSrc.removeCallbacks(mTriggerLongPress);
+        }
+
+        if (mDisallowIntercept != null) {
+            mSrc.removeCallbacks(mDisallowIntercept);
+        }
+    }
+
+    private void onLongPress() {
+        clearCallbacks();
+
+        final View src = mSrc;
+        if (!src.isEnabled() || src.isLongClickable()) {
+            // Ignore long-press if the view is disabled or has its own
+            // handler.
+            return;
+        }
+
+        if (!onForwardingStarted()) {
+            return;
+        }
+
+        // Don't let the parent intercept our events.
+        src.getParent().requestDisallowInterceptTouchEvent(true);
+
+        // Make sure we cancel any ongoing source event stream.
+        final long now = SystemClock.uptimeMillis();
+        final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
+        src.onTouchEvent(e);
+        e.recycle();
+
+        mForwarding = true;
+        mWasLongPress = true;
+    }
+
+    /**
+     * Handles forwarded motion events and determines when to stop
+     * forwarding.
+     *
+     * @param srcEvent motion event in source view coordinates
+     * @return true to continue forwarding motion events, false to cancel
+     */
+    private boolean onTouchForwarded(MotionEvent srcEvent) {
+        final View src = mSrc;
+        final ShowableListMenu popup = getPopup();
+        if (popup == null || !popup.isShowing()) {
+            return false;
+        }
+
+        final DropDownListView dst = (DropDownListView) popup.getListView();
+        if (dst == null || !dst.isShown()) {
+            return false;
+        }
+
+        // Convert event to destination-local coordinates.
+        final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
+        src.toGlobalMotionEvent(dstEvent);
+        dst.toLocalMotionEvent(dstEvent);
+
+        // Forward converted event to destination view, then recycle it.
+        final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
+        dstEvent.recycle();
+
+        // Always cancel forwarding when the touch stream ends.
+        final int action = srcEvent.getActionMasked();
+        final boolean keepForwarding = action != MotionEvent.ACTION_UP
+                && action != MotionEvent.ACTION_CANCEL;
+
+        return handled && keepForwarding;
+    }
+
+    private class DisallowIntercept implements Runnable {
+        @Override
+        public void run() {
+            final ViewParent parent = mSrc.getParent();
+            parent.requestDisallowInterceptTouchEvent(true);
+        }
+    }
+
+    private class TriggerLongPress implements Runnable {
+        @Override
+        public void run() {
+            onLongPress();
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index a02efcf..3d07d87 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -25,7 +25,6 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
-import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.IntProperty;
@@ -36,13 +35,13 @@
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.View.OnTouchListener;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.WindowManager;
 import android.view.animation.AccelerateDecelerateInterpolator;
 
 import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
 import com.android.internal.widget.AutoScrollHelper.AbsListViewAutoScroller;
 
 import java.util.Locale;
@@ -58,7 +57,7 @@
  * @see android.widget.AutoCompleteTextView
  * @see android.widget.Spinner
  */
-public class ListPopupWindow {
+public class ListPopupWindow implements ShowableListMenu {
     private static final String TAG = "ListPopupWindow";
     private static final boolean DEBUG = false;
 
@@ -580,6 +579,7 @@
      * Show the popup list. If the list is already showing, this method
      * will recalculate the popup's size and position.
      */
+    @Override
     public void show() {
         int height = buildDropDown();
 
@@ -671,6 +671,7 @@
     /**
      * Dismiss the popup window.
      */
+    @Override
     public void dismiss() {
         mPopup.dismiss();
         removePromptView();
@@ -732,7 +733,7 @@
     public void setSelection(int position) {
         DropDownListView list = mDropDownList;
         if (isShowing() && list != null) {
-            list.mListSelectionHidden = false;
+            list.setListSelectionHidden(false);
             list.setSelection(position);
             if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
                 list.setItemChecked(position, true);
@@ -748,7 +749,7 @@
         final DropDownListView list = mDropDownList;
         if (list != null) {
             // WARNING: Please read the comment where mListSelectionHidden is declared
-            list.mListSelectionHidden = true;
+            list.setListSelectionHidden(true);
             list.hideSelector();
             list.requestLayout();
         }
@@ -757,6 +758,7 @@
     /**
      * @return {@code true} if the popup is currently showing, {@code false} otherwise.
      */
+    @Override
     public boolean isShowing() {
         return mPopup.isShowing();
     }
@@ -842,6 +844,7 @@
      * @return The {@link ListView} displayed within the popup window.
      * Only valid when {@link #isShowing()} == {@code true}.
      */
+    @Override
     public ListView getListView() {
         return mDropDownList;
     }
@@ -911,7 +914,7 @@
                 } else {
                     // WARNING: Please read the comment where mListSelectionHidden
                     //          is declared
-                    mDropDownList.mListSelectionHidden = false;
+                    mDropDownList.setListSelectionHidden(false);
                 }
 
                 consumed = mDropDownList.onKeyDown(keyCode, event);
@@ -1037,7 +1040,7 @@
     public OnTouchListener createDragToOpenListener(View src) {
         return new ForwardingListener(src) {
             @Override
-            public ListPopupWindow getPopup() {
+            public ShowableListMenu getPopup() {
                 return ListPopupWindow.this;
             }
         };
@@ -1088,7 +1091,7 @@
                         DropDownListView dropDownList = mDropDownList;
 
                         if (dropDownList != null) {
-                            dropDownList.mListSelectionHidden = false;
+                            dropDownList.setListSelectionHidden(false);
                         }
                     }
                 }
@@ -1219,568 +1222,6 @@
         return listContent + otherHeights;
     }
 
-    /**
-     * Abstract class that forwards touch events to a {@link ListPopupWindow}.
-     *
-     * @hide
-     */
-    public static abstract class ForwardingListener
-            implements View.OnTouchListener, View.OnAttachStateChangeListener {
-        /** Scaled touch slop, used for detecting movement outside bounds. */
-        private final float mScaledTouchSlop;
-
-        /** Timeout before disallowing intercept on the source's parent. */
-        private final int mTapTimeout;
-
-        /** Timeout before accepting a long-press to start forwarding. */
-        private final int mLongPressTimeout;
-
-        /** Source view from which events are forwarded. */
-        private final View mSrc;
-
-        /** Runnable used to prevent conflicts with scrolling parents. */
-        private Runnable mDisallowIntercept;
-
-        /** Runnable used to trigger forwarding on long-press. */
-        private Runnable mTriggerLongPress;
-
-        /** Whether this listener is currently forwarding touch events. */
-        private boolean mForwarding;
-
-        /**
-         * Whether forwarding was initiated by a long-press. If so, we won't
-         * force the window to dismiss when the touch stream ends.
-         */
-        private boolean mWasLongPress;
-
-        /** The id of the first pointer down in the current event stream. */
-        private int mActivePointerId;
-
-        public ForwardingListener(View src) {
-            mSrc = src;
-            mScaledTouchSlop = ViewConfiguration.get(src.getContext()).getScaledTouchSlop();
-            mTapTimeout = ViewConfiguration.getTapTimeout();
-
-            // Use a medium-press timeout. Halfway between tap and long-press.
-            mLongPressTimeout = (mTapTimeout + ViewConfiguration.getLongPressTimeout()) / 2;
-
-            src.addOnAttachStateChangeListener(this);
-        }
-
-        /**
-         * Returns the popup to which this listener is forwarding events.
-         * <p>
-         * Override this to return the correct popup. If the popup is displayed
-         * asynchronously, you may also need to override
-         * {@link #onForwardingStopped} to prevent premature cancelation of
-         * forwarding.
-         *
-         * @return the popup to which this listener is forwarding events
-         */
-        public abstract ListPopupWindow getPopup();
-
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            final boolean wasForwarding = mForwarding;
-            final boolean forwarding;
-            if (wasForwarding) {
-                forwarding = onTouchForwarded(event) || !onForwardingStopped();
-            } else {
-                forwarding = onTouchObserved(event) && onForwardingStarted();
-
-                if (forwarding) {
-                    // Make sure we cancel any ongoing source event stream.
-                    final long now = SystemClock.uptimeMillis();
-                    final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL,
-                            0.0f, 0.0f, 0);
-                    mSrc.onTouchEvent(e);
-                    e.recycle();
-                }
-            }
-
-            mForwarding = forwarding;
-            return forwarding || wasForwarding;
-        }
-
-        @Override
-        public void onViewAttachedToWindow(View v) {
-        }
-
-        @Override
-        public void onViewDetachedFromWindow(View v) {
-            mForwarding = false;
-            mActivePointerId = MotionEvent.INVALID_POINTER_ID;
-
-            if (mDisallowIntercept != null) {
-                mSrc.removeCallbacks(mDisallowIntercept);
-            }
-        }
-
-        /**
-         * Called when forwarding would like to start.
-         * <p>
-         * By default, this will show the popup returned by {@link #getPopup()}.
-         * It may be overridden to perform another action, like clicking the
-         * source view or preparing the popup before showing it.
-         *
-         * @return true to start forwarding, false otherwise
-         */
-        protected boolean onForwardingStarted() {
-            final ListPopupWindow popup = getPopup();
-            if (popup != null && !popup.isShowing()) {
-                popup.show();
-            }
-            return true;
-        }
-
-        /**
-         * Called when forwarding would like to stop.
-         * <p>
-         * By default, this will dismiss the popup returned by
-         * {@link #getPopup()}. It may be overridden to perform some other
-         * action.
-         *
-         * @return true to stop forwarding, false otherwise
-         */
-        protected boolean onForwardingStopped() {
-            final ListPopupWindow popup = getPopup();
-            if (popup != null && popup.isShowing()) {
-                popup.dismiss();
-            }
-            return true;
-        }
-
-        /**
-         * Observes motion events and determines when to start forwarding.
-         *
-         * @param srcEvent motion event in source view coordinates
-         * @return true to start forwarding motion events, false otherwise
-         */
-        private boolean onTouchObserved(MotionEvent srcEvent) {
-            final View src = mSrc;
-            if (!src.isEnabled()) {
-                return false;
-            }
-
-            final int actionMasked = srcEvent.getActionMasked();
-            switch (actionMasked) {
-                case MotionEvent.ACTION_DOWN:
-                    mActivePointerId = srcEvent.getPointerId(0);
-                    mWasLongPress = false;
-
-                    if (mDisallowIntercept == null) {
-                        mDisallowIntercept = new DisallowIntercept();
-                    }
-                    src.postDelayed(mDisallowIntercept, mTapTimeout);
-
-                    if (mTriggerLongPress == null) {
-                        mTriggerLongPress = new TriggerLongPress();
-                    }
-                    src.postDelayed(mTriggerLongPress, mLongPressTimeout);
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    final int activePointerIndex = srcEvent.findPointerIndex(mActivePointerId);
-                    if (activePointerIndex >= 0) {
-                        final float x = srcEvent.getX(activePointerIndex);
-                        final float y = srcEvent.getY(activePointerIndex);
-
-                        // Has the pointer has moved outside of the view?
-                        if (!src.pointInView(x, y, mScaledTouchSlop)) {
-                            clearCallbacks();
-
-                            // Don't let the parent intercept our events.
-                            src.getParent().requestDisallowInterceptTouchEvent(true);
-                            return true;
-                        }
-                    }
-                    break;
-                case MotionEvent.ACTION_CANCEL:
-                case MotionEvent.ACTION_UP:
-                    clearCallbacks();
-                    break;
-            }
-
-            return false;
-        }
-
-        private void clearCallbacks() {
-            if (mTriggerLongPress != null) {
-                mSrc.removeCallbacks(mTriggerLongPress);
-            }
-
-            if (mDisallowIntercept != null) {
-                mSrc.removeCallbacks(mDisallowIntercept);
-            }
-        }
-
-        private void onLongPress() {
-            clearCallbacks();
-
-            final View src = mSrc;
-            if (!src.isEnabled() || src.isLongClickable()) {
-                // Ignore long-press if the view is disabled or has its own
-                // handler.
-                return;
-            }
-
-            if (!onForwardingStarted()) {
-                return;
-            }
-
-            // Don't let the parent intercept our events.
-            src.getParent().requestDisallowInterceptTouchEvent(true);
-
-            // Make sure we cancel any ongoing source event stream.
-            final long now = SystemClock.uptimeMillis();
-            final MotionEvent e = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0);
-            src.onTouchEvent(e);
-            e.recycle();
-
-            mForwarding = true;
-            mWasLongPress = true;
-        }
-
-        /**
-         * Handled forwarded motion events and determines when to stop
-         * forwarding.
-         *
-         * @param srcEvent motion event in source view coordinates
-         * @return true to continue forwarding motion events, false to cancel
-         */
-        private boolean onTouchForwarded(MotionEvent srcEvent) {
-            final View src = mSrc;
-            final ListPopupWindow popup = getPopup();
-            if (popup == null || !popup.isShowing()) {
-                return false;
-            }
-
-            final DropDownListView dst = popup.mDropDownList;
-            if (dst == null || !dst.isShown()) {
-                return false;
-            }
-
-            // Convert event to destination-local coordinates.
-            final MotionEvent dstEvent = MotionEvent.obtainNoHistory(srcEvent);
-            src.toGlobalMotionEvent(dstEvent);
-            dst.toLocalMotionEvent(dstEvent);
-
-            // Forward converted event to destination view, then recycle it.
-            final boolean handled = dst.onForwardedEvent(dstEvent, mActivePointerId);
-            dstEvent.recycle();
-
-            // Always cancel forwarding when the touch stream ends.
-            final int action = srcEvent.getActionMasked();
-            final boolean keepForwarding = action != MotionEvent.ACTION_UP
-                    && action != MotionEvent.ACTION_CANCEL;
-
-            return handled && keepForwarding;
-        }
-
-        private class DisallowIntercept implements Runnable {
-            @Override
-            public void run() {
-                final ViewParent parent = mSrc.getParent();
-                parent.requestDisallowInterceptTouchEvent(true);
-            }
-        }
-
-        private class TriggerLongPress implements Runnable {
-            @Override
-            public void run() {
-                onLongPress();
-            }
-        }
-    }
-
-    /**
-     * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
-     * make sure the list uses the appropriate drawables and states when
-     * displayed on screen within a drop down. The focus is never actually
-     * passed to the drop down in this mode; the list only looks focused.</p>
-     */
-    static class DropDownListView extends ListView {
-        /** Duration in milliseconds of the drag-to-open click animation. */
-        private static final long CLICK_ANIM_DURATION = 150;
-
-        /** Target alpha value for drag-to-open click animation. */
-        private static final int CLICK_ANIM_ALPHA = 0x80;
-
-        /** Wrapper around Drawable's <code>alpha</code> property. */
-        private static final IntProperty<Drawable> DRAWABLE_ALPHA =
-                new IntProperty<Drawable>("alpha") {
-                    @Override
-                    public void setValue(Drawable object, int value) {
-                        object.setAlpha(value);
-                    }
-
-                    @Override
-                    public Integer get(Drawable object) {
-                        return object.getAlpha();
-                    }
-                };
-
-        /*
-         * WARNING: This is a workaround for a touch mode issue.
-         *
-         * Touch mode is propagated lazily to windows. This causes problems in
-         * the following scenario:
-         * - Type something in the AutoCompleteTextView and get some results
-         * - Move down with the d-pad to select an item in the list
-         * - Move up with the d-pad until the selection disappears
-         * - Type more text in the AutoCompleteTextView *using the soft keyboard*
-         *   and get new results; you are now in touch mode
-         * - The selection comes back on the first item in the list, even though
-         *   the list is supposed to be in touch mode
-         *
-         * Using the soft keyboard triggers the touch mode change but that change
-         * is propagated to our window only after the first list layout, therefore
-         * after the list attempts to resurrect the selection.
-         *
-         * The trick to work around this issue is to pretend the list is in touch
-         * mode when we know that the selection should not appear, that is when
-         * we know the user moved the selection away from the list.
-         *
-         * This boolean is set to true whenever we explicitly hide the list's
-         * selection and reset to false whenever we know the user moved the
-         * selection back to the list.
-         *
-         * When this boolean is true, isInTouchMode() returns true, otherwise it
-         * returns super.isInTouchMode().
-         */
-        private boolean mListSelectionHidden;
-        
-        /**
-         * True if this wrapper should fake focus.
-         */
-        private boolean mHijackFocus;
-
-        /** Whether to force drawing of the pressed state selector. */
-        private boolean mDrawsInPressedState;
-
-        /** Current drag-to-open click animation, if any. */
-        private Animator mClickAnimation;
-
-        /** Helper for drag-to-open auto scrolling. */
-        private AbsListViewAutoScroller mScrollHelper;
-
-        /**
-         * <p>Creates a new list view wrapper.</p>
-         *
-         * @param context this view's context
-         */
-        public DropDownListView(Context context, boolean hijackFocus) {
-            super(context, null, com.android.internal.R.attr.dropDownListViewStyle);
-            mHijackFocus = hijackFocus;
-            // TODO: Add an API to control this
-            setCacheColorHint(0); // Transparent, since the background drawable could be anything.
-        }
-
-        /**
-         * Handles forwarded events.
-         *
-         * @param activePointerId id of the pointer that activated forwarding
-         * @return whether the event was handled
-         */
-        public boolean onForwardedEvent(MotionEvent event, int activePointerId) {
-            boolean handledEvent = true;
-            boolean clearPressedItem = false;
-
-            final int actionMasked = event.getActionMasked();
-            switch (actionMasked) {
-                case MotionEvent.ACTION_CANCEL:
-                    handledEvent = false;
-                    break;
-                case MotionEvent.ACTION_UP:
-                    handledEvent = false;
-                    // $FALL-THROUGH$
-                case MotionEvent.ACTION_MOVE:
-                    final int activeIndex = event.findPointerIndex(activePointerId);
-                    if (activeIndex < 0) {
-                        handledEvent = false;
-                        break;
-                    }
-
-                    final int x = (int) event.getX(activeIndex);
-                    final int y = (int) event.getY(activeIndex);
-                    final int position = pointToPosition(x, y);
-                    if (position == INVALID_POSITION) {
-                        clearPressedItem = true;
-                        break;
-                    }
-
-                    final View child = getChildAt(position - getFirstVisiblePosition());
-                    setPressedItem(child, position, x, y);
-                    handledEvent = true;
-
-                    if (actionMasked == MotionEvent.ACTION_UP) {
-                        clickPressedItem(child, position);
-                    }
-                    break;
-            }
-
-            // Failure to handle the event cancels forwarding.
-            if (!handledEvent || clearPressedItem) {
-                clearPressedItem();
-            }
-
-            // Manage automatic scrolling.
-            if (handledEvent) {
-                if (mScrollHelper == null) {
-                    mScrollHelper = new AbsListViewAutoScroller(this);
-                }
-                mScrollHelper.setEnabled(true);
-                mScrollHelper.onTouch(this, event);
-            } else if (mScrollHelper != null) {
-                mScrollHelper.setEnabled(false);
-            }
-
-            return handledEvent;
-        }
-
-        /**
-         * Starts an alpha animation on the selector. When the animation ends,
-         * the list performs a click on the item.
-         */
-        private void clickPressedItem(final View child, final int position) {
-            final long id = getItemIdAtPosition(position);
-            final Animator anim = ObjectAnimator.ofInt(
-                    mSelector, DRAWABLE_ALPHA, 0xFF, CLICK_ANIM_ALPHA, 0xFF);
-            anim.setDuration(CLICK_ANIM_DURATION);
-            anim.setInterpolator(new AccelerateDecelerateInterpolator());
-            anim.addListener(new AnimatorListenerAdapter() {
-                    @Override
-                public void onAnimationEnd(Animator animation) {
-                    performItemClick(child, position, id);
-                }
-            });
-            anim.start();
-
-            if (mClickAnimation != null) {
-                mClickAnimation.cancel();
-            }
-            mClickAnimation = anim;
-        }
-
-        private void clearPressedItem() {
-            mDrawsInPressedState = false;
-            setPressed(false);
-            updateSelectorState();
-
-            final View motionView = getChildAt(mMotionPosition - mFirstPosition);
-            if (motionView != null) {
-                motionView.setPressed(false);
-            }
-
-            if (mClickAnimation != null) {
-                mClickAnimation.cancel();
-                mClickAnimation = null;
-            }
-        }
-
-        private void setPressedItem(View child, int position, float x, float y) {
-            mDrawsInPressedState = true;
-
-            // Ordering is essential. First, update the container's pressed state.
-            drawableHotspotChanged(x, y);
-            if (!isPressed()) {
-                setPressed(true);
-            }
-
-            // Next, run layout if we need to stabilize child positions.
-            if (mDataChanged) {
-                layoutChildren();
-            }
-
-            // Manage the pressed view based on motion position. This allows us to
-            // play nicely with actual touch and scroll events.
-            final View motionView = getChildAt(mMotionPosition - mFirstPosition);
-            if (motionView != null && motionView != child && motionView.isPressed()) {
-                motionView.setPressed(false);
-            }
-            mMotionPosition = position;
-
-            // Offset for child coordinates.
-            final float childX = x - child.getLeft();
-            final float childY = y - child.getTop();
-            child.drawableHotspotChanged(childX, childY);
-            if (!child.isPressed()) {
-                child.setPressed(true);
-            }
-
-            // Ensure that keyboard focus starts from the last touched position.
-            setSelectedPositionInt(position);
-            positionSelectorLikeTouch(position, child, x, y);
-
-            // Refresh the drawable state to reflect the new pressed state,
-            // which will also update the selector state.
-            refreshDrawableState();
-
-            if (mClickAnimation != null) {
-                mClickAnimation.cancel();
-                mClickAnimation = null;
-            }
-        }
-
-        @Override
-        boolean touchModeDrawsInPressedState() {
-            return mDrawsInPressedState || super.touchModeDrawsInPressedState();
-        }
-
-        /**
-         * <p>Avoids jarring scrolling effect by ensuring that list elements
-         * made of a text view fit on a single line.</p>
-         *
-         * @param position the item index in the list to get a view for
-         * @return the view for the specified item
-         */
-        @Override
-        View obtainView(int position, boolean[] isScrap) {
-            View view = super.obtainView(position, isScrap);
-
-            if (view instanceof TextView) {
-                ((TextView) view).setHorizontallyScrolling(true);
-            }
-
-            return view;
-        }
-
-        @Override
-        public boolean isInTouchMode() {
-            // WARNING: Please read the comment where mListSelectionHidden is declared
-            return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
-        }
-
-        /**
-         * <p>Returns the focus state in the drop down.</p>
-         *
-         * @return true always if hijacking focus
-         */
-        @Override
-        public boolean hasWindowFocus() {
-            return mHijackFocus || super.hasWindowFocus();
-        }
-
-        /**
-         * <p>Returns the focus state in the drop down.</p>
-         *
-         * @return true always if hijacking focus
-         */
-        @Override
-        public boolean isFocused() {
-            return mHijackFocus || super.isFocused();
-        }
-
-        /**
-         * <p>Returns the focus state in the drop down.</p>
-         *
-         * @return true always if hijacking focus
-         */
-        @Override
-        public boolean hasFocus() {
-            return mHijackFocus || super.hasFocus();
-        }
-    }
-
     private class PopupDataSetObserver extends DataSetObserver {
         @Override
         public void onChanged() {
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index 8d42c73..9e47e85 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -36,11 +36,11 @@
     }
 
     @Override
-    ListPopupWindow.DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
+    DropDownListView createDropDownListView(Context context, boolean hijackFocus) {
         return new MenuDropDownListView(context, hijackFocus);
     }
 
-    static class MenuDropDownListView extends ListPopupWindow.DropDownListView {
+    static class MenuDropDownListView extends DropDownListView {
         private boolean mHoveredOnDisabledItem = false;
         private AccessibilityManager mAccessibilityManager;
 
diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java
index 1507dfb..3b2d60d 100644
--- a/core/java/android/widget/PopupMenu.java
+++ b/core/java/android/widget/PopupMenu.java
@@ -20,6 +20,7 @@
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuPresenter;
+import com.android.internal.view.menu.ShowableListMenu;
 import com.android.internal.view.menu.SubMenuBuilder;
 
 import android.annotation.MenuRes;
@@ -30,7 +31,6 @@
 import android.view.MenuItem;
 import android.view.View;
 import android.view.View.OnTouchListener;
-import android.widget.ListPopupWindow.ForwardingListener;
 
 /**
  * A PopupMenu displays a {@link Menu} in a modal popup window anchored to a {@link View}.
@@ -170,7 +170,7 @@
                 }
 
                 @Override
-                public ListPopupWindow getPopup() {
+                public ShowableListMenu getPopup() {
                     // This will be null until show() is called.
                     return mPopup.getPopup();
                 }
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index 6e04eac..e9325ef 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -26,6 +26,7 @@
 import android.graphics.Paint.Style;
 import android.graphics.Rect;
 import android.graphics.Typeface;
+import android.icu.text.SimpleDateFormat;
 import android.os.Bundle;
 import android.text.TextPaint;
 import android.text.format.DateFormat;
@@ -43,7 +44,6 @@
 import com.android.internal.widget.ExploreByTouchHelper;
 
 import java.text.NumberFormat;
-import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Locale;
 
diff --git a/core/java/android/widget/Spinner.java b/core/java/android/widget/Spinner.java
index f3cf61c..c79e184 100644
--- a/core/java/android/widget/Spinner.java
+++ b/core/java/android/widget/Spinner.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import com.android.internal.R;
+import com.android.internal.view.menu.ShowableListMenu;
 
 import android.annotation.DrawableRes;
 import android.annotation.Nullable;
@@ -44,7 +45,6 @@
 import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.ListPopupWindow.ForwardingListener;
 import android.widget.PopupWindow.OnDismissListener;
 
 /**
@@ -278,7 +278,7 @@
                 mPopup = popup;
                 mForwardingListener = new ForwardingListener(this) {
                     @Override
-                    public ListPopupWindow getPopup() {
+                    public ShowableListMenu getPopup() {
                         return popup;
                     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7a64377..61402ab 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -21,6 +21,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Size;
 import android.annotation.StringRes;
 import android.annotation.StyleRes;
 import android.annotation.XmlRes;
@@ -103,6 +104,7 @@
 import android.text.style.UpdateAppearance;
 import android.text.util.Linkify;
 import android.util.AttributeSet;
+import android.util.LocaleList;
 import android.util.Log;
 import android.util.TypedValue;
 import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -553,7 +555,7 @@
     private final TextPaint mTextPaint;
     private boolean mUserSetTextScaleX;
     private Layout mLayout;
-    private boolean mLocaleChanged = false;
+    private boolean mLocalesChanged = false;
 
     @ViewDebug.ExportedProperty(category = "text")
     private int mGravity = Gravity.TOP | Gravity.START;
@@ -2817,32 +2819,58 @@
     }
 
     /**
-     * Get the default {@link Locale} of the text in this TextView.
-     * @return the default {@link Locale} of the text in this TextView.
+     * Get the default primary {@link Locale} of the text in this TextView. This will always be
+     * the first member of {@link #getTextLocales()}.
+     * @return the default primary {@link Locale} of the text in this TextView.
      */
+    @NonNull
     public Locale getTextLocale() {
         return mTextPaint.getTextLocale();
     }
 
     /**
-     * Set the default {@link Locale} of the text in this TextView to the given value. This value
-     * is used to choose appropriate typefaces for ambiguous characters. Typically used for CJK
-     * locales to disambiguate Hanzi/Kanji/Hanja characters.
+     * Get the default {@link LocaleList} of the text in this TextView.
+     * @return the default {@link LocaleList} of the text in this TextView.
+     */
+    @NonNull @Size(min=1)
+    public LocaleList getTextLocales() {
+        return mTextPaint.getTextLocales();
+    }
+
+    /**
+     * Set the default {@link LocaleList} of the text in this TextView to a one-member list
+     * containing just the given value.
      *
      * @param locale the {@link Locale} for drawing text, must not be null.
      *
-     * @see Paint#setTextLocale
+     * @see #setTextLocales
      */
-    public void setTextLocale(Locale locale) {
-        mLocaleChanged = true;
+    public void setTextLocale(@NonNull Locale locale) {
+        mLocalesChanged = true;
         mTextPaint.setTextLocale(locale);
     }
 
+    /**
+     * Set the default {@link LocaleList} of the text in this TextView to the given value.
+     *
+     * This value is used to choose appropriate typefaces for ambiguous characters (typically used
+     * for CJK locales to disambiguate Hanzi/Kanji/Hanja characters). It also affects
+     * other aspects of text display, including line breaking.
+     *
+     * @param locales the {@link LocaleList} for drawing text, must not be null or empty.
+     *
+     * @see Paint#setTextLocales
+     */
+    public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+        mLocalesChanged = true;
+        mTextPaint.setTextLocales(locales);
+    }
+
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        if (!mLocaleChanged) {
-            mTextPaint.setTextLocale(Locale.getDefault());
+        if (!mLocalesChanged) {
+            mTextPaint.setTextLocales(LocaleList.getDefault());
         }
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f178c8c..4f4d3e0 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -338,7 +338,7 @@
         }
 
         if (mCpuPowerCalculator == null) {
-            mCpuPowerCalculator = new CpuPowerCalculator(mPowerProfile);
+            mCpuPowerCalculator = new CpuPowerCalculator();
         }
         mCpuPowerCalculator.reset();
 
diff --git a/core/java/com/android/internal/os/CpuPowerCalculator.java b/core/java/com/android/internal/os/CpuPowerCalculator.java
index a3ef612..d62f7a6 100644
--- a/core/java/com/android/internal/os/CpuPowerCalculator.java
+++ b/core/java/com/android/internal/os/CpuPowerCalculator.java
@@ -23,54 +23,14 @@
     private static final String TAG = "CpuPowerCalculator";
     private static final boolean DEBUG = BatteryStatsHelper.DEBUG;
 
-    private final double[] mPowerCpuNormal;
-
-    /**
-     * Reusable array for calculations.
-     */
-    private final long[] mSpeedStepTimes;
-
-    public CpuPowerCalculator(PowerProfile profile) {
-        final int speedSteps = profile.getNumSpeedSteps();
-        mPowerCpuNormal = new double[speedSteps];
-        mSpeedStepTimes = new long[speedSteps];
-        for (int p = 0; p < speedSteps; p++) {
-            mPowerCpuNormal[p] = profile.getAveragePower(PowerProfile.POWER_CPU_ACTIVE, p);
-        }
-    }
-
     @Override
     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
                              long rawUptimeUs, int statsType) {
-        final int speedSteps = mSpeedStepTimes.length;
-
-        long totalTimeAtSpeeds = 0;
-        for (int step = 0; step < speedSteps; step++) {
-            mSpeedStepTimes[step] = u.getTimeAtCpuSpeed(step, statsType);
-            totalTimeAtSpeeds += mSpeedStepTimes[step];
-        }
-        totalTimeAtSpeeds = Math.max(totalTimeAtSpeeds, 1);
-
         app.cpuTimeMs = (u.getUserCpuTimeUs(statsType) + u.getSystemCpuTimeUs(statsType)) / 1000;
-        if (DEBUG && app.cpuTimeMs != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": CPU time " + app.cpuTimeMs + " ms");
-        }
-
-        double cpuPowerMaMs = 0;
-        for (int step = 0; step < speedSteps; step++) {
-            final double ratio = (double) mSpeedStepTimes[step] / totalTimeAtSpeeds;
-            final double cpuSpeedStepPower = ratio * app.cpuTimeMs * mPowerCpuNormal[step];
-            if (DEBUG && ratio != 0) {
-                Log.d(TAG, "UID " + u.getUid() + ": CPU step #"
-                        + step + " ratio=" + BatteryStatsHelper.makemAh(ratio) + " power="
-                        + BatteryStatsHelper.makemAh(cpuSpeedStepPower / (60 * 60 * 1000)));
-            }
-            cpuPowerMaMs += cpuSpeedStepPower;
-        }
-
-        if (DEBUG && cpuPowerMaMs != 0) {
-            Log.d(TAG, "UID " + u.getUid() + ": cpu total power="
-                    + BatteryStatsHelper.makemAh(cpuPowerMaMs / (60 * 60 * 1000)));
+        app.cpuPowerMah = (double) u.getCpuPowerMaUs(statsType) / (60.0 * 60.0 * 1000.0 * 1000.0);
+        if (DEBUG && (app.cpuTimeMs != 0 || app.cpuPowerMah != 0)) {
+            Log.d(TAG, "UID " + u.getUid() + ": CPU time=" + app.cpuTimeMs + " ms power="
+                    + BatteryStatsHelper.makemAh(app.cpuPowerMah));
         }
 
         // Keep track of the package with highest drain.
@@ -108,8 +68,5 @@
             // Statistics may not have been gathered yet.
             app.cpuTimeMs = app.cpuFgTimeMs;
         }
-
-        // Convert the CPU power to mAh
-        app.cpuPowerMah = cpuPowerMaMs / (60 * 60 * 1000);
     }
 }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9ca937c..af73097 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -179,9 +179,15 @@
 
     static void preload() {
         Log.d(TAG, "begin preload");
+        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClasses");
         preloadClasses();
+        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadResources");
         preloadResources();
+        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+        Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadOpenGL");
         preloadOpenGL();
+        Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
         preloadSharedLibraries();
         preloadTextResources();
         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
@@ -265,6 +271,7 @@
                     continue;
                 }
 
+                Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadClass " + line);
                 try {
                     if (false) {
                         Log.v(TAG, "Preloading " + line + "...");
@@ -290,6 +297,7 @@
                     }
                     throw new RuntimeException(t);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
             }
 
             Log.i(TAG, "...preloaded " + count + " classes in "
@@ -302,7 +310,9 @@
             runtime.setTargetHeapUtilization(defaultUtilization);
 
             // Fill in dex caches with classes, fields, and methods brought in by preloading.
+            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PreloadDexCaches");
             runtime.preloadDexCaches();
+            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
 
             // Bring back root. We'll need it later if we're in the zygote.
             if (droppedPriviliges) {
@@ -564,6 +574,7 @@
 
     public static void main(String argv[]) {
         try {
+            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygoteInit");
             RuntimeInit.enableDdms();
             // Start profiling the zygote initialization.
             SamplingProfilerIntegration.start();
@@ -588,17 +599,23 @@
             }
 
             registerZygoteSocket(socketName);
+            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "ZygotePreload");
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
                 SystemClock.uptimeMillis());
             preload();
             EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
                 SystemClock.uptimeMillis());
+            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
 
             // Finish profiling the zygote initialization.
             SamplingProfilerIntegration.writeZygoteSnapshot();
 
             // Do an initial gc to clean up after startup
+            Trace.traceBegin(Trace.TRACE_TAG_DALVIK, "PostZygoteInitGC");
             gcAndFinalize();
+            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
+
+            Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
 
             // Disable tracing so that forked processes do not inherit stale tracing tags from
             // Zygote.
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 9761661..44df0ce 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -76,6 +76,15 @@
         mMenu = new MenuBuilder(context).setDefaultShowAsAction(
                 MenuItem.SHOW_AS_ACTION_IF_ROOM);
         setType(ActionMode.TYPE_FLOATING);
+        mMenu.setCallback(new MenuBuilder.Callback() {
+            @Override
+            public void onMenuModeChange(MenuBuilder menu) {}
+
+            @Override
+            public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+                return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+            }
+        });
         mContentRect = new Rect();
         mContentRectOnScreen = new Rect();
         mPreviousContentRectOnScreen = new Rect();
@@ -99,7 +108,7 @@
                 .setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
                         @Override
                     public boolean onMenuItemClick(MenuItem item) {
-                        return mCallback.onActionItemClicked(FloatingActionMode.this, item);
+                        return mMenu.performItemAction(item, 0);
                     }
                 });
         mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 8db363d..ce5bc90 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -29,10 +29,10 @@
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.ActionMenuView;
+import android.widget.ForwardingListener;
 import android.widget.ListPopupWindow;
 import android.widget.TextView;
 import android.widget.Toast;
-import android.widget.ListPopupWindow.ForwardingListener;
 
 /**
  * @hide
@@ -320,7 +320,7 @@
         }
 
         @Override
-        public ListPopupWindow getPopup() {
+        public ShowableListMenu getPopup() {
             if (mPopupCallback != null) {
                 return mPopupCallback.getPopup();
             }
@@ -331,7 +331,7 @@
         protected boolean onForwardingStarted() {
             // Call the invoker, then check if the expected popup is showing.
             if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) {
-                final ListPopupWindow popup = getPopup();
+                final ShowableListMenu popup = getPopup();
                 return popup != null && popup.isShowing();
             }
             return false;
@@ -339,7 +339,7 @@
 
         @Override
         protected boolean onForwardingStopped() {
-            final ListPopupWindow popup = getPopup();
+            final ShowableListMenu popup = getPopup();
             if (popup != null) {
                 popup.dismiss();
                 return true;
@@ -349,6 +349,6 @@
     }
 
     public static abstract class PopupCallback {
-        public abstract ListPopupWindow getPopup();
+        public abstract ShowableListMenu getPopup();
     }
 }
diff --git a/core/java/com/android/internal/view/menu/ListMenuItemView.java b/core/java/com/android/internal/view/menu/ListMenuItemView.java
index 29ac3f3..2526393 100644
--- a/core/java/com/android/internal/view/menu/ListMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ListMenuItemView.java
@@ -43,11 +43,13 @@
     private TextView mTitleView;
     private CheckBox mCheckBox;
     private TextView mShortcutView;
+    private ImageView mSubMenuArrowView;
     
     private Drawable mBackground;
     private int mTextAppearance;
     private Context mTextAppearanceContext;
     private boolean mPreserveIconSpacing;
+    private Drawable mSubMenuArrow;
     
     private int mMenuType;
     
@@ -68,6 +70,7 @@
         mPreserveIconSpacing = a.getBoolean(
                 com.android.internal.R.styleable.MenuView_preserveIconSpacing, false);
         mTextAppearanceContext = context;
+        mSubMenuArrow = a.getDrawable(com.android.internal.R.styleable.MenuView_subMenuArrow);
         
         a.recycle();
     }
@@ -77,7 +80,7 @@
     }
 
     public ListMenuItemView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
+        this(context, attrs, com.android.internal.R.attr.listMenuViewStyle);
     }
 
     @Override
@@ -93,6 +96,10 @@
         }
         
         mShortcutView = (TextView) findViewById(com.android.internal.R.id.shortcut);
+        mSubMenuArrowView = (ImageView) findViewById(com.android.internal.R.id.submenuarrow);
+        if (mSubMenuArrowView != null) {
+            mSubMenuArrowView.setImageDrawable(mSubMenuArrow);
+        }
     }
 
     public void initialize(MenuItemImpl itemData, int menuType) {
@@ -106,6 +113,7 @@
         setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
         setIcon(itemData.getIcon());
         setEnabled(itemData.isEnabled());
+        setSubMenuArrowVisible(itemData.hasSubMenu());
     }
 
     public void setForceShowIcon(boolean forceShow) {
@@ -186,6 +194,12 @@
         compoundButton.setChecked(checked);
     }
 
+    private void setSubMenuArrowVisible(boolean hasSubmenu) {
+        if (mSubMenuArrowView != null) {
+            mSubMenuArrowView.setVisibility(hasSubmenu ? View.VISIBLE : View.GONE);
+        }
+    }
+
     public void setShortcut(boolean showShortcut, char shortcutKey) {
         final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
                 ? VISIBLE : GONE;
diff --git a/core/java/com/android/internal/view/menu/MenuAdapter.java b/core/java/com/android/internal/view/menu/MenuAdapter.java
new file mode 100644
index 0000000..1e03b1f
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuAdapter.java
@@ -0,0 +1,109 @@
+/*
+ * 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.menu;
+
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.util.ArrayList;
+
+public class MenuAdapter extends BaseAdapter {
+    static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
+
+    MenuBuilder mAdapterMenu;
+
+    private int mExpandedIndex = -1;
+
+    private boolean mForceShowIcon;
+    private final boolean mOverflowOnly;
+    private final LayoutInflater mInflater;
+
+    public MenuAdapter(MenuBuilder menu, LayoutInflater inflater, boolean overflowOnly) {
+        mOverflowOnly = overflowOnly;
+        mInflater = inflater;
+        mAdapterMenu = menu;
+        findExpandedIndex();
+    }
+
+    public void setForceShowIcon(boolean forceShow) {
+        mForceShowIcon = forceShow;
+    }
+
+    public int getCount() {
+        ArrayList<MenuItemImpl> items = mOverflowOnly ?
+                mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+        if (mExpandedIndex < 0) {
+            return items.size();
+        }
+        return items.size() - 1;
+    }
+
+    public MenuBuilder getAdapterMenu() {
+        return mAdapterMenu;
+    }
+
+    public MenuItemImpl getItem(int position) {
+        ArrayList<MenuItemImpl> items = mOverflowOnly ?
+                mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
+        if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
+            position++;
+        }
+        return items.get(position);
+    }
+
+    public long getItemId(int position) {
+        // Since a menu item's ID is optional, we'll use the position as an
+        // ID for the item in the AdapterView
+        return position;
+    }
+
+    public View getView(int position, View convertView, ViewGroup parent) {
+        if (convertView == null) {
+            convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
+        }
+
+        MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+        if (mForceShowIcon) {
+            ((ListMenuItemView) convertView).setForceShowIcon(true);
+        }
+        itemView.initialize(getItem(position), 0);
+        return convertView;
+    }
+
+    void findExpandedIndex() {
+        final MenuItemImpl expandedItem = mAdapterMenu.getExpandedItem();
+        if (expandedItem != null) {
+            final ArrayList<MenuItemImpl> items = mAdapterMenu.getNonActionItems();
+            final int count = items.size();
+            for (int i = 0; i < count; i++) {
+                final MenuItemImpl item = items.get(i);
+                if (item == expandedItem) {
+                    mExpandedIndex = i;
+                    return;
+                }
+            }
+        }
+        mExpandedIndex = -1;
+    }
+
+    @Override
+    public void notifyDataSetChanged() {
+        findExpandedIndex();
+        super.notifyDataSetChanged();
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
new file mode 100644
index 0000000..91788ca
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -0,0 +1,122 @@
+/*
+ * 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.menu;
+
+import android.content.Context;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ListAdapter;
+import android.widget.PopupWindow;
+
+/**
+ * Base class for a menu popup abstraction - i.e., some type of menu, housed in a popup window
+ * environment.
+ *
+ * @hide
+ */
+public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
+
+    public abstract void setForceShowIcon(boolean forceShow);
+
+    /**
+     * Adds the given menu to the popup. If this is the first menu shown it'll be displayed; if it's
+     * a submenu it will be displayed adjacent to the most recent menu (if supported by the
+     * implementation).
+     *
+     * @param menu
+     */
+    public abstract void addMenu(MenuBuilder menu);
+
+    public abstract void setGravity(int dropDownGravity);
+
+    public abstract void setAnchorView(View anchor);
+
+    /**
+     * Set a listener to receive a callback when the popup is dismissed.
+     *
+     * @param listener Listener that will be notified when the popup is dismissed.
+     */
+    public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener);
+
+    @Override
+    public void initForMenu(Context context, MenuBuilder menu) {
+        // Don't need to do anything; we added as a presenter in the constructor.
+    }
+
+    @Override
+    public MenuView getMenuView(ViewGroup root) {
+        throw new UnsupportedOperationException("MenuPopups manage their own views");
+    }
+
+    @Override
+    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+        return false;
+    }
+
+    @Override
+    public int getId() {
+        return 0;
+    }
+
+    /**
+     * Measures the width of the given menu view.
+     *
+     * @param view The view to measure.
+     * @return The width.
+     */
+    protected static int measureIndividualMenuWidth(ListAdapter adapter, ViewGroup parent,
+            Context context, int maxAllowedWidth) {
+        // Menus don't tend to be long, so this is more sane than it looks.
+        int maxWidth = 0;
+        View itemView = null;
+        int itemType = 0;
+
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        final int count = adapter.getCount();
+        for (int i = 0; i < count; i++) {
+            final int positionType = adapter.getItemViewType(i);
+            if (positionType != itemType) {
+                itemType = positionType;
+                itemView = null;
+            }
+
+            if (parent == null) {
+                parent = new FrameLayout(context);
+            }
+
+            itemView = adapter.getView(i, itemView, parent);
+            itemView.measure(widthMeasureSpec, heightMeasureSpec);
+
+            final int itemWidth = itemView.getMeasuredWidth();
+            if (itemWidth >= maxAllowedWidth) {
+                return maxAllowedWidth;
+            } else if (itemWidth > maxWidth) {
+                maxWidth = itemWidth;
+            }
+        }
+
+        return maxWidth;
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index 13654a6..9a47fc1 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -17,57 +17,29 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
-import android.content.res.Resources;
 import android.os.Parcelable;
 import android.view.Gravity;
-import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
 import android.view.View;
-import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
-import android.widget.BaseAdapter;
-import android.widget.FrameLayout;
-import android.widget.ListAdapter;
-import android.widget.MenuPopupWindow;
 import android.widget.PopupWindow;
 
-import java.util.ArrayList;
-
 /**
  * Presents a menu as a small, simple popup anchored to another view.
+ *
  * @hide
  */
-public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
-        ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
-        View.OnAttachStateChangeListener, MenuPresenter {
-    static final int ITEM_LAYOUT = com.android.internal.R.layout.popup_menu_item_layout;
-
+public class MenuPopupHelper implements ViewTreeObserver.OnGlobalLayoutListener,
+        PopupWindow.OnDismissListener, View.OnAttachStateChangeListener, MenuPresenter {
     private final Context mContext;
-    private final LayoutInflater mInflater;
     private final MenuBuilder mMenu;
-    private final MenuAdapter mAdapter;
     private final boolean mOverflowOnly;
-    private final int mPopupMaxWidth;
     private final int mPopupStyleAttr;
     private final int mPopupStyleRes;
 
     private View mAnchorView;
-    private MenuPopupWindow mPopup;
+    private MenuPopup mPopup;
     private ViewTreeObserver mTreeObserver;
-    private Callback mPresenterCallback;
-
-    boolean mForceShowIcon;
-
-    private ViewGroup mMeasureParent;
-
-    /** Whether the cached content width value is valid. */
-    private boolean mHasContentWidth;
-
-    /** Cached content width from {@link #measureContentWidth}. */
-    private int mContentWidth;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
@@ -87,33 +59,37 @@
     public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView,
             boolean overflowOnly, int popupStyleAttr, int popupStyleRes) {
         mContext = context;
-        mInflater = LayoutInflater.from(context);
         mMenu = menu;
-        mAdapter = new MenuAdapter(mMenu);
         mOverflowOnly = overflowOnly;
         mPopupStyleAttr = popupStyleAttr;
         mPopupStyleRes = popupStyleRes;
-
-        final Resources res = context.getResources();
-        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
-                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
-
         mAnchorView = anchorView;
+        mPopup = createMenuPopup();
+    }
 
-        // Present the menu using our context, not the menu builder's context.
-        menu.addMenuPresenter(this, context);
+    private MenuPopup createMenuPopup() {
+        if (mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_enableCascadingSubmenus)) {
+            // TODO: Return a Cascading implementation of MenuPopup instead.
+            return new StandardMenuPopup(
+                    mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
+        }
+        return new StandardMenuPopup(
+                mContext, mMenu, mAnchorView, mPopupStyleAttr, mPopupStyleRes, mOverflowOnly);
     }
 
     public void setAnchorView(View anchor) {
         mAnchorView = anchor;
+        mPopup.setAnchorView(anchor);
     }
 
     public void setForceShowIcon(boolean forceShow) {
-        mForceShowIcon = forceShow;
+        mPopup.setForceShowIcon(forceShow);
     }
 
     public void setGravity(int gravity) {
         mDropDownGravity = gravity;
+        mPopup.setGravity(gravity);
     }
 
     public int getGravity() {
@@ -126,28 +102,21 @@
         }
     }
 
-    public MenuPopupWindow getPopup() {
+    public ShowableListMenu getPopup() {
         return mPopup;
     }
 
     /**
-     * Attempts to show the popup anchored to the view specified by
-     * {@link #setAnchorView(View)}.
+     * Attempts to show the popup anchored to the view specified by {@link #setAnchorView(View)}.
      *
-     * @return {@code true} if the popup was shown or was already showing prior
-     *         to calling this method, {@code false} otherwise
+     * @return {@code true} if the popup was shown or was already showing prior to calling this
+     *         method, {@code false} otherwise
      */
     public boolean tryShow() {
         if (isShowing()) {
             return true;
         }
 
-        mPopup = new MenuPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
-        mPopup.setOnDismissListener(this);
-        mPopup.setOnItemClickListener(this);
-        mPopup.setAdapter(mAdapter);
-        mPopup.setModal(true);
-
         final View anchor = mAnchorView;
         if (anchor != null) {
             final boolean addGlobalListener = mTreeObserver == null;
@@ -155,20 +124,19 @@
             if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
             anchor.addOnAttachStateChangeListener(this);
             mPopup.setAnchorView(anchor);
-            mPopup.setDropDownGravity(mDropDownGravity);
+            mPopup.setGravity(mDropDownGravity);
         } else {
             return false;
         }
 
-        if (!mHasContentWidth) {
-            mContentWidth = measureContentWidth();
-            mHasContentWidth = true;
-        }
+        // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface,
+        // we must set the listener to this outer Helper rather than to the inner MenuPopup.
+        // Not to worry -- the inner MenuPopup will call our own #onDismiss method after it's done
+        // its own handling.
+        mPopup.setOnDismissListener(this);
 
-        mPopup.setContentWidth(mContentWidth);
-        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.addMenu(mMenu);
         mPopup.show();
-        mPopup.getListView().setOnKeyListener(this);
         return true;
     }
 
@@ -181,7 +149,6 @@
     @Override
     public void onDismiss() {
         mPopup = null;
-        mMenu.close();
         if (mTreeObserver != null) {
             if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
             mTreeObserver.removeGlobalOnLayoutListener(this);
@@ -195,56 +162,6 @@
     }
 
     @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        MenuAdapter adapter = mAdapter;
-        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
-    }
-
-    @Override
-    public boolean onKey(View v, int keyCode, KeyEvent event) {
-        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
-            dismiss();
-            return true;
-        }
-        return false;
-    }
-
-    private int measureContentWidth() {
-        // Menus don't tend to be long, so this is more sane than it looks.
-        int maxWidth = 0;
-        View itemView = null;
-        int itemType = 0;
-
-        final ListAdapter adapter = mAdapter;
-        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
-        final int count = adapter.getCount();
-        for (int i = 0; i < count; i++) {
-            final int positionType = adapter.getItemViewType(i);
-            if (positionType != itemType) {
-                itemType = positionType;
-                itemView = null;
-            }
-
-            if (mMeasureParent == null) {
-                mMeasureParent = new FrameLayout(mContext);
-            }
-
-            itemView = adapter.getView(i, itemView, mMeasureParent);
-            itemView.measure(widthMeasureSpec, heightMeasureSpec);
-
-            final int itemWidth = itemView.getMeasuredWidth();
-            if (itemWidth >= mPopupMaxWidth) {
-                return mPopupMaxWidth;
-            } else if (itemWidth > maxWidth) {
-                maxWidth = itemWidth;
-            }
-        }
-
-        return maxWidth;
-    }
-
-    @Override
     public void onGlobalLayout() {
         if (isShowing()) {
             final View anchor = mAnchorView;
@@ -282,54 +199,22 @@
 
     @Override
     public void updateMenuView(boolean cleared) {
-        mHasContentWidth = false;
-
-        if (mAdapter != null) {
-            mAdapter.notifyDataSetChanged();
-        }
+        mPopup.updateMenuView(cleared);
     }
 
     @Override
     public void setCallback(Callback cb) {
-        mPresenterCallback = cb;
+        mPopup.setCallback(cb);
     }
 
     @Override
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
-        if (subMenu.hasVisibleItems()) {
-            MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView);
-            subPopup.setCallback(mPresenterCallback);
-
-            boolean preserveIconSpacing = false;
-            final int count = subMenu.size();
-            for (int i = 0; i < count; i++) {
-                MenuItem childItem = subMenu.getItem(i);
-                if (childItem.isVisible() && childItem.getIcon() != null) {
-                    preserveIconSpacing = true;
-                    break;
-                }
-            }
-            subPopup.setForceShowIcon(preserveIconSpacing);
-
-            if (subPopup.tryShow()) {
-                if (mPresenterCallback != null) {
-                    mPresenterCallback.onOpenSubMenu(subMenu);
-                }
-                return true;
-            }
-        }
-        return false;
+        return mPopup.onSubMenuSelected(subMenu);
     }
 
     @Override
     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
-        // Only care about the (sub)menu we're presenting.
-        if (menu != mMenu) return;
-
-        dismiss();
-        if (mPresenterCallback != null) {
-            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
-        }
+        mPopup.onCloseMenu(menu, allMenusAreClosing);
     }
 
     @Override
@@ -337,10 +222,12 @@
         return false;
     }
 
+    @Override
     public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
 
+    @Override
     public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
         return false;
     }
@@ -358,73 +245,4 @@
     @Override
     public void onRestoreInstanceState(Parcelable state) {
     }
-
-    private class MenuAdapter extends BaseAdapter {
-        private MenuBuilder mAdapterMenu;
-        private int mExpandedIndex = -1;
-
-        public MenuAdapter(MenuBuilder menu) {
-            mAdapterMenu = menu;
-            findExpandedIndex();
-        }
-
-        public int getCount() {
-            ArrayList<MenuItemImpl> items = mOverflowOnly ?
-                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
-            if (mExpandedIndex < 0) {
-                return items.size();
-            }
-            return items.size() - 1;
-        }
-
-        public MenuItemImpl getItem(int position) {
-            ArrayList<MenuItemImpl> items = mOverflowOnly ?
-                    mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
-            if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
-                position++;
-            }
-            return items.get(position);
-        }
-
-        public long getItemId(int position) {
-            // Since a menu item's ID is optional, we'll use the position as an
-            // ID for the item in the AdapterView
-            return position;
-        }
-
-        public View getView(int position, View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
-            }
-
-            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
-            if (mForceShowIcon) {
-                ((ListMenuItemView) convertView).setForceShowIcon(true);
-            }
-            itemView.initialize(getItem(position), 0);
-            return convertView;
-        }
-
-        void findExpandedIndex() {
-            final MenuItemImpl expandedItem = mMenu.getExpandedItem();
-            if (expandedItem != null) {
-                final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
-                final int count = items.size();
-                for (int i = 0; i < count; i++) {
-                    final MenuItemImpl item = items.get(i);
-                    if (item == expandedItem) {
-                        mExpandedIndex = i;
-                        return;
-                    }
-                }
-            }
-            mExpandedIndex = -1;
-        }
-
-        @Override
-        public void notifyDataSetChanged() {
-            findExpandedIndex();
-            super.notifyDataSetChanged();
-        }
-    }
 }
diff --git a/core/java/com/android/internal/view/menu/ShowableListMenu.java b/core/java/com/android/internal/view/menu/ShowableListMenu.java
new file mode 100644
index 0000000..ca158fd
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ShowableListMenu.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import android.widget.ListView;
+
+/**
+ * A list menu which can be shown and hidden and which is internally represented by a ListView.
+ */
+public interface ShowableListMenu {
+    public void show();
+
+    public void dismiss();
+
+    public boolean isShowing();
+
+    /**
+     * @return The internal ListView for the visible menu.
+     */
+    public ListView getListView();
+}
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
new file mode 100644
index 0000000..9a30ffa
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -0,0 +1,246 @@
+package com.android.internal.view.menu;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Parcelable;
+import android.view.Gravity;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.OnKeyListener;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import android.widget.MenuPopupWindow;
+import android.widget.PopupWindow;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.PopupWindow.OnDismissListener;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * A standard menu popup in which when a submenu is opened, it replaces its parent menu in the
+ * viewport.
+ */
+final class StandardMenuPopup extends MenuPopup implements OnDismissListener, OnItemClickListener,
+        MenuPresenter, OnKeyListener {
+
+    private final Context mContext;
+    private final LayoutInflater mInflater;
+    private final MenuBuilder mMenu;
+    private final MenuAdapter mAdapter;
+    private final boolean mOverflowOnly;
+    private final int mPopupMaxWidth;
+    private final int mPopupStyleAttr;
+    private final int mPopupStyleRes;
+
+    private PopupWindow.OnDismissListener mOnDismissListener;
+
+    private View mAnchorView;
+    private MenuPopupWindow mPopup;
+    private Callback mPresenterCallback;
+
+    private ViewGroup mMeasureParent;
+
+    /** Whether the cached content width value is valid. */
+    private boolean mHasContentWidth;
+
+    /** Cached content width. */
+    private int mContentWidth;
+
+    private int mDropDownGravity = Gravity.NO_GRAVITY;
+
+    public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
+            int popupStyleRes, boolean overflowOnly) {
+        mContext = Preconditions.checkNotNull(context);
+        mInflater = LayoutInflater.from(context);
+        mMenu = menu;
+        mOverflowOnly = overflowOnly;
+        mAdapter = new MenuAdapter(menu, mInflater, mOverflowOnly);
+        mPopupStyleAttr = popupStyleAttr;
+        mPopupStyleRes = popupStyleRes;
+
+        final Resources res = context.getResources();
+        mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
+                res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
+
+        mAnchorView = anchorView;
+
+        mPopup = new MenuPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes);
+
+        // Present the menu using our context, not the menu builder's context.
+        menu.addMenuPresenter(this, context);
+    }
+
+    @Override
+    public void setForceShowIcon(boolean forceShow) {
+        mAdapter.setForceShowIcon(forceShow);
+    }
+
+    @Override
+    public void setGravity(int gravity) {
+        mDropDownGravity = gravity;
+    }
+
+    private boolean tryShow() {
+        if (isShowing()) {
+            return true;
+        }
+
+        mPopup.setOnDismissListener(this);
+        mPopup.setOnItemClickListener(this);
+        mPopup.setAdapter(mAdapter);
+        mPopup.setModal(true);
+
+        final View anchor = mAnchorView;
+        if (anchor != null) {
+            mPopup.setAnchorView(anchor);
+            mPopup.setDropDownGravity(mDropDownGravity);
+        } else {
+            return false;
+        }
+
+        if (!mHasContentWidth) {
+            mContentWidth = measureIndividualMenuWidth(
+                    mAdapter, mMeasureParent, mContext, mPopupMaxWidth);
+            mHasContentWidth = true;
+        }
+
+        mPopup.setContentWidth(mContentWidth);
+        mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.show();
+        mPopup.getListView().setOnKeyListener(this);
+        return true;
+    }
+
+    @Override
+    public void show() {
+        if (!tryShow()) {
+            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
+        }
+    }
+
+    @Override
+    public void dismiss() {
+        if (isShowing()) {
+            mPopup.dismiss();
+        }
+    }
+
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        MenuAdapter adapter = mAdapter;
+        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
+    }
+
+    @Override
+    public void addMenu(MenuBuilder menu) {
+        // No-op: standard implementation has only one menu which is set in the constructor.
+    }
+
+    @Override
+    public boolean isShowing() {
+        return mPopup != null && mPopup.isShowing();
+    }
+
+    @Override
+    public void onDismiss() {
+        mPopup = null;
+        mMenu.close();
+
+        mOnDismissListener.onDismiss();
+    }
+
+    @Override
+    public void updateMenuView(boolean cleared) {
+        mHasContentWidth = false;
+
+        if (mAdapter != null) {
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    @Override
+    public void setCallback(Callback cb) {
+        mPresenterCallback = cb;
+    }
+
+    @Override
+    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+        if (subMenu.hasVisibleItems()) {
+            MenuPopupHelper subPopup = new MenuPopupHelper(
+                    mContext, subMenu, mAnchorView, mOverflowOnly, mPopupStyleAttr, mPopupStyleRes);
+            subPopup.setCallback(mPresenterCallback);
+
+            boolean preserveIconSpacing = false;
+            final int count = subMenu.size();
+            for (int i = 0; i < count; i++) {
+                MenuItem childItem = subMenu.getItem(i);
+                if (childItem.isVisible() && childItem.getIcon() != null) {
+                    preserveIconSpacing = true;
+                    break;
+                }
+            }
+            subPopup.setForceShowIcon(preserveIconSpacing);
+
+            if (subPopup.tryShow()) {
+                if (mPresenterCallback != null) {
+                    mPresenterCallback.onOpenSubMenu(subMenu);
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        // Only care about the (sub)menu we're presenting.
+        if (menu != mMenu) return;
+
+        dismiss();
+        if (mPresenterCallback != null) {
+            mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
+        }
+    }
+
+    @Override
+    public boolean flagActionItems() {
+        return false;
+    }
+
+
+    @Override
+    public Parcelable onSaveInstanceState() {
+        return null;
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+    }
+
+    @Override
+    public void setAnchorView(View anchor) {
+        mAnchorView = anchor;
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+        if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
+            dismiss();
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public void setOnDismissListener(OnDismissListener listener) {
+        mOnDismissListener = listener;
+    }
+
+    @Override
+    public ListView getListView() {
+        return mPopup.getListView();
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 35eeca7..582c4f1 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -19,6 +19,7 @@
 
 import android.util.TypedValue;
 import android.view.ContextThemeWrapper;
+import android.view.MotionEvent;
 import android.widget.ActionMenuPresenter;
 import android.widget.ActionMenuView;
 
@@ -53,6 +54,9 @@
 
     protected Animator mVisibilityAnim;
 
+    private boolean mEatingTouch;
+    private boolean mEatingHover;
+
     public AbsActionBarView(Context context) {
         this(context, null);
     }
@@ -97,6 +101,57 @@
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        // ActionBarViews always eat touch events, but should still respect the touch event dispatch
+        // contract. If the normal View implementation doesn't want the events, we'll just silently
+        // eat the rest of the gesture without reporting the events to the default implementation
+        // since that's what it expects.
+
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_DOWN) {
+            mEatingTouch = false;
+        }
+
+        if (!mEatingTouch) {
+            final boolean handled = super.onTouchEvent(ev);
+            if (action == MotionEvent.ACTION_DOWN && !handled) {
+                mEatingTouch = true;
+            }
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            mEatingTouch = false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean onHoverEvent(MotionEvent ev) {
+        // Same deal as onTouchEvent() above. Eat all hover events, but still
+        // respect the touch event dispatch contract.
+
+        final int action = ev.getActionMasked();
+        if (action == MotionEvent.ACTION_HOVER_ENTER) {
+            mEatingHover = false;
+        }
+
+        if (!mEatingHover) {
+            final boolean handled = super.onHoverEvent(ev);
+            if (action == MotionEvent.ACTION_HOVER_ENTER && !handled) {
+                mEatingHover = true;
+            }
+        }
+
+        if (action == MotionEvent.ACTION_HOVER_EXIT
+                || action == MotionEvent.ACTION_CANCEL) {
+            mEatingHover = false;
+        }
+
+        return true;
+    }
+
     /**
      * Sets whether the bar should be split right now, no questions asked.
      * @param split true if the bar should split
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 0579ce7..d96a909 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -232,7 +232,7 @@
     public void reportFailedPasswordAttempt(int userId) {
         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
-        requireCredentialEntry(userId);
+        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL, userId);
     }
 
     public void reportSuccessfulPasswordAttempt(int userId) {
@@ -456,7 +456,7 @@
             // well, we tried...
         }
 
-        if (userHandle == UserHandle.USER_OWNER) {
+        if (userHandle == UserHandle.USER_SYSTEM) {
             // Set the encryption password to default.
             updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
         }
@@ -516,7 +516,7 @@
             DevicePolicyManager dpm = getDevicePolicyManager();
 
             // Update the device encryption password.
-            if (userId == UserHandle.USER_OWNER
+            if (userId == UserHandle.USER_SYSTEM
                     && LockPatternUtils.isDeviceEncryptionEnabled()) {
                 if (!shouldEncryptWithCredentials(true)) {
                     clearEncryptionPassword();
@@ -538,7 +538,7 @@
     }
 
     private void updateCryptoUserInfo(int userId) {
-        if (userId != UserHandle.USER_OWNER) {
+        if (userId != UserHandle.USER_SYSTEM) {
             return;
         }
 
@@ -714,7 +714,7 @@
             int computedQuality = computePasswordQuality(password);
 
             // Update the device encryption password.
-            if (userHandle == UserHandle.USER_OWNER
+            if (userHandle == UserHandle.USER_SYSTEM
                     && LockPatternUtils.isDeviceEncryptionEnabled()) {
                 if (!shouldEncryptWithCredentials(true)) {
                     clearEncryptionPassword();
@@ -1008,7 +1008,7 @@
         setBoolean(Settings.Secure.LOCK_PATTERN_VISIBLE, enabled, userId);
 
         // Update for crypto if owner
-        if (userId != UserHandle.USER_OWNER) {
+        if (userId != UserHandle.USER_SYSTEM) {
             return;
         }
 
@@ -1031,7 +1031,7 @@
      */
     public void setVisiblePasswordEnabled(boolean enabled, int userId) {
         // Update for crypto if owner
-        if (userId != UserHandle.USER_OWNER) {
+        if (userId != UserHandle.USER_SYSTEM) {
             return;
         }
 
@@ -1178,7 +1178,7 @@
      * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
      */
     public void requireCredentialEntry(int userId) {
-        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+        requireStrongAuth(StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
     }
 
     /**
@@ -1210,7 +1210,7 @@
     }
 
     public void setCredentialRequiredToDecrypt(boolean required) {
-        if (ActivityManager.getCurrentUser() != UserHandle.USER_OWNER) {
+        if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
             Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
             return;
         }
@@ -1260,7 +1260,7 @@
                 value = { STRONG_AUTH_NOT_REQUIRED,
                         STRONG_AUTH_REQUIRED_AFTER_BOOT,
                         STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
-                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+                        STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST})
         @Retention(RetentionPolicy.SOURCE)
         public @interface StrongAuthFlags {}
 
@@ -1275,14 +1275,14 @@
         public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
 
         /**
-         * Strong authentication is required because a device admin has requested it.
+         * Strong authentication is required because a device admin has temporarily requested it.
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
 
         /**
-         * Some authentication is required because the user has temporarily disabled trust.
+         * Strong authentication is required because the user has temporarily requested it.
          */
-        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+        public static final int STRONG_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
 
         /**
          * Strong authentication is required because the user has been locked out after too many
@@ -1290,11 +1290,17 @@
          */
         public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
 
+        /**
+         * Some authentication is required because the user has entered a wrong credential.
+         */
+        public static final int SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL = 0x10;
+
         public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
-        private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
 
-        final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
+        private static final int ALLOWING_FINGERPRINT = STRONG_AUTH_NOT_REQUIRED
+                | SOME_AUTH_REQUIRED_AFTER_WRONG_CREDENTIAL;
 
+        private final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
         private final H mHandler;
 
         public StrongAuthTracker() {
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 372d934..491b323 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -128,6 +128,8 @@
                     // When there is no decor we should not react to anything.
                     return false;
                 }
+                // Ensure that the activity is active.
+                activateActivity();
                 // A drag action is started if we aren't dragging already and the starting event is
                 // either a left mouse button or any other input device.
                 if (!mDragging &&
@@ -346,4 +348,18 @@
             }
         }
     }
+
+    /**
+     * Activates the activity - means setting the focus and moving it to the top of the stack.
+     */
+    private void activateActivity() {
+        Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback();
+        if (callback != null) {
+            try {
+                callback.activateActivity();
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Failed to activate the activity.");
+            }
+        }
+    }
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f7a2f9f..e4bc800 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#define ATRACE_TAG ATRACE_TAG_DALVIK
 #define LOG_TAG "AndroidRuntime"
 //#define LOG_NDEBUG 0
 
@@ -23,6 +24,7 @@
 #include <binder/IServiceManager.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
+#include <utils/Trace.h>
 #include <binder/Parcel.h>
 #include <utils/threads.h>
 #include <cutils/properties.h>
@@ -1437,6 +1439,7 @@
  */
 /*static*/ int AndroidRuntime::startReg(JNIEnv* env)
 {
+    ATRACE_NAME("RegisterAndroidNatives");
     /*
      * This hook causes all future threads created in this process to be
      * attached to the JavaVM.  (This needs to go away in favor of JNI
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index e10a644..8b69bbd 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -755,48 +755,31 @@
 // ----------------------------------------------------------------------------
 
 /**
- * Given a buffer crop rectangle relative to the pixel array size, and the pre-correction active
- * array crop rectangle for the camera characteristics, set the default crop rectangle in the
- * TiffWriter relative to the buffer crop rectangle origin.
+ * Calculate the default crop relative to the "active area" of the image sensor (this active area
+ * will always be the pre-correction active area rectangle), and set this.
  */
 static status_t calculateAndSetCrop(JNIEnv* env, const CameraMetadata& characteristics,
-        uint32_t bufWidth, uint32_t bufHeight, sp<TiffWriter> writer) {
+        sp<TiffWriter> writer) {
 
     camera_metadata_ro_entry entry =
             characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
-    uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
-    uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
     uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
     uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
 
     const uint32_t margin = 8; // Default margin recommended by Adobe for interpolation.
 
-    // Crop based on pre-correction array for pixel array
-    uint32_t aLeft = xmin;
-    uint32_t aTop = ymin;
-    uint32_t aRight = xmin + width;
-    uint32_t aBottom = ymin + height;
-
-    // 8 pixel border crop for pixel array dimens
-    uint32_t bLeft = margin;
-    uint32_t bTop = margin;
-    uint32_t bRight = bufWidth - margin;
-    uint32_t bBottom = bufHeight - margin;
-
-    // Set the crop to be the intersection of the two rectangles
-    uint32_t defaultCropOrigin[] = {std::max(aLeft, bLeft), std::max(aTop, bTop)};
-    uint32_t defaultCropSize[] = {std::min(aRight, bRight) - defaultCropOrigin[0],
-            std::min(aBottom, bBottom) - defaultCropOrigin[1]};
-
-    // If using buffers with  pre-correction array dimens, switch to 8 pixel border crop
-    // relative to the pixel array dimens
-    if (bufWidth == width && bufHeight == height) {
-        defaultCropOrigin[0] = xmin + margin;
-        defaultCropOrigin[1] = ymin + margin;
-        defaultCropSize[0] = width - margin;
-        defaultCropSize[1] = height - margin;
+    if (width < margin * 2 || height < margin * 2) {
+        ALOGE("%s: Cannot calculate default crop for image, pre-correction active area is too"
+                "small: h=%" PRIu32 ", w=%" PRIu32, __FUNCTION__, height, width);
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Pre-correction active area is too small.");
+        return BAD_VALUE;
     }
 
+    uint32_t defaultCropOrigin[] = {margin, margin};
+    uint32_t defaultCropSize[] = {width - defaultCropOrigin[0] - margin,
+                                  height - defaultCropOrigin[1] - margin};
+
     BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPORIGIN, 2, defaultCropOrigin,
             TIFF_IFD_0), env, TAG_DEFAULTCROPORIGIN, writer);
     BAIL_IF_INVALID_R(writer->addEntry(TAG_DEFAULTCROPSIZE, 2, defaultCropSize,
@@ -1565,17 +1548,24 @@
 
     {
         // Set dimensions
-        if (calculateAndSetCrop(env, characteristics, imageWidth, imageHeight, writer) != OK) {
+        if (calculateAndSetCrop(env, characteristics, writer) != OK) {
             return nullptr;
         }
         camera_metadata_entry entry =
                 characteristics.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
-        BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_DEFAULTCROPSIZE, writer);
+        BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_ACTIVEAREA, writer);
         uint32_t xmin = static_cast<uint32_t>(entry.data.i32[0]);
         uint32_t ymin = static_cast<uint32_t>(entry.data.i32[1]);
         uint32_t width = static_cast<uint32_t>(entry.data.i32[2]);
         uint32_t height = static_cast<uint32_t>(entry.data.i32[3]);
 
+        // If we only have a buffer containing the pre-correction rectangle, ignore the offset
+        // relative to the pixel array.
+        if (imageWidth == width && imageHeight == height) {
+            xmin = 0;
+            ymin = 0;
+        }
+
         uint32_t activeArea[] = {ymin, xmin, ymin + height, xmin + width};
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ACTIVEAREA, 4, activeArea, TIFF_IFD_0),
                 env, TAG_ACTIVEAREA, writer);
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 54be410..d1acb59 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -57,6 +57,7 @@
     jfieldID secure;
     jfieldID appVsyncOffsetNanos;
     jfieldID presentationDeadlineNanos;
+    jfieldID colorTransform;
 } gPhysicalDisplayInfoClassInfo;
 
 static struct {
@@ -394,6 +395,8 @@
                 info.appVsyncOffset);
         env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
                 info.presentationDeadline);
+        env->SetIntField(infoObj, gPhysicalDisplayInfoClassInfo.colorTransform,
+                info.colorTransform);
         env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
         env->DeleteLocalRef(infoObj);
     }
@@ -656,6 +659,8 @@
             clazz, "appVsyncOffsetNanos", "J");
     gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = GetFieldIDOrDie(env,
             clazz, "presentationDeadlineNanos", "J");
+    gPhysicalDisplayInfoClassInfo.colorTransform = GetFieldIDOrDie(env, clazz,
+            "colorTransform", "I");
 
     jclass rectClazz = FindClassOrDie(env, "android/graphics/Rect");
     gRectClassInfo.bottom = GetFieldIDOrDie(env, rectClazz, "bottom", "I");
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 47132f4..6c3676b 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -418,6 +418,12 @@
     proxy->notifyFramePending();
 }
 
+static void android_view_ThreadedRenderer_serializeDisplayListTree(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->serializeDisplayListTree();
+}
+
 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -483,6 +489,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 },
+    { "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
     { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
     { "nDumpProfileData", "([BLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileData },
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 414cbb4..aef70be 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -83,6 +83,14 @@
   pid_t pid;
   int status;
 
+  // It's necessary to save and restore the errno during this function.
+  // Since errno is stored per thread, changing it here modifies the errno
+  // on the thread on which this signal handler executes. If a signal occurs
+  // between a call and an errno check, it's possible to get the errno set
+  // here.
+  // See b/23572286 for extra information.
+  int saved_errno = errno;
+
   while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
      // Log process-death status that we care about.  In general it is
      // not safe to call LOG(...) from a signal handler because of
@@ -118,6 +126,8 @@
   if (pid < 0 && errno != ECHILD) {
     ALOGW("Zygote SIGCHLD error in waitpid: %s", strerror(errno));
   }
+
+  errno = saved_errno;
 }
 
 // Configures the SIGCHLD handler for the zygote process. This is configured
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b0621e9..d6657dd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2069,6 +2069,12 @@
     <permission android:name="android.permission.SET_KEYBOARD_LAYOUT"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to monitor changes in tablet mode.
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.TABLET_MODE_LISTENER"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to request installing packages. Apps
          targeting APIs greater than 22 must hold this permission in
          order to use {@link android.content.Intent#ACTION_INSTALL_PACKAGE}.
diff --git a/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml b/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml
new file mode 100644
index 0000000..2dd0540
--- /dev/null
+++ b/core/res/res/drawable/ic_arrow_drop_right_black_24dp.xml
@@ -0,0 +1,34 @@
+<?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.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="25.0dp"
+    android:viewportHeight="25.0"
+    android:viewportWidth="24.0"
+    android:width="25.0dp"
+    android:tint="?attr/colorControlNormal"
+    android:autoMirrored="true">
+
+    <group
+        android:name="arrow"
+        android:rotation="90.0"
+        android:pivotX="12.0"
+        android:pivotY="13.0"
+        android:translateY="1.0">
+        <path android:fillColor="#000000" android:pathData="M7,14 L12,9 L17,14 L7,14 Z" />
+        <path android:pathData="M0,0 L24,0 L24,24 L0,24 L0,0 Z" />
+    </group>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/non_client_decor_dark.xml b/core/res/res/layout/non_client_decor_dark.xml
index d1e2974..112f4b7 100644
--- a/core/res/res/layout/non_client_decor_dark.xml
+++ b/core/res/res/layout/non_client_decor_dark.xml
@@ -26,7 +26,9 @@
         android:layout_width="match_parent"
         android:layout_gravity="end"
         android:layout_height="wrap_content"
-        android:background="@drawable/non_client_decor_title" >
+        android:background="@drawable/non_client_decor_title"
+        android:focusable="false"
+        android:descendantFocusability="blocksDescendants" >
         <TextView
             android:layout_width="0dp"
             android:layout_height="match_parent"
@@ -40,7 +42,7 @@
             android:layout_gravity="center_vertical|end"
             android:contentDescription="@string/maximize_button_text"
             android:background="@drawable/decor_maximize_button_dark" />
-         <Button
+        <Button
             android:id="@+id/close_window"
             android:layout_width="32dp"
             android:layout_height="32dp"
diff --git a/core/res/res/layout/non_client_decor_light.xml b/core/res/res/layout/non_client_decor_light.xml
index f7c3fcd..5dd79c7 100644
--- a/core/res/res/layout/non_client_decor_light.xml
+++ b/core/res/res/layout/non_client_decor_light.xml
@@ -26,7 +26,9 @@
         android:layout_width="match_parent"
         android:layout_gravity="end"
         android:layout_height="wrap_content"
-        android:background="@drawable/non_client_decor_title" >
+        android:background="@drawable/non_client_decor_title"
+        android:focusable="false"
+        android:descendantFocusability="blocksDescendants" >
         <TextView
             android:layout_width="0dp"
             android:layout_height="match_parent"
@@ -40,7 +42,7 @@
             android:layout_gravity="center_vertical|end"
             android:contentDescription="@string/maximize_button_text"
             android:background="@drawable/decor_maximize_button_light" />
-         <Button
+        <Button
             android:id="@+id/close_window"
             android:layout_width="32dp"
             android:layout_height="32dp"
diff --git a/core/res/res/layout/popup_menu_item_layout.xml b/core/res/res/layout/popup_menu_item_layout.xml
index 0bc636f..8b8c93a 100644
--- a/core/res/res/layout/popup_menu_item_layout.xml
+++ b/core/res/res/layout/popup_menu_item_layout.xml
@@ -57,6 +57,15 @@
 
     </RelativeLayout>
 
+    <ImageView
+        android:id="@+id/submenuarrow"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center"
+        android:layout_marginStart="8dp"
+        android:scaleType="center"
+        android:visibility="gone" />
+
     <!-- Checkbox, and/or radio button will be inserted here. -->
     
 </com.android.internal.view.menu.ListMenuItemView>
diff --git a/core/res/res/values-af-watch/strings.xml b/core/res/res/values-af-watch/strings.xml
index 9dc98a1..ee43129 100644
--- a/core/res/res/values-af-watch/strings.xml
+++ b/core/res/res/values-af-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Program <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensors"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"verkry toegang tot jou kontakte"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"verkry toegang tot hierdie horlosie se ligging"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"verkry toegang tot jou kalender"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"stuur en bekyk SMS-boodskappe"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"verkry toegang tot foto\'s, media en lêers op jou horlosie"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"neem oudio op"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"neem foto\'s en neem video op"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"maak en bestuur foonoproepe"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"verkry toegang tot sensordata oor jou lewenstekens"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"wees die statusbalk"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"verkry toegang tot liggaamsensors (soos hartklopmonitors)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"verkry toegang tot presiese ligging (GPS- en netwerkgegrond)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"verkry toegang tot benaderde ligging (netwerkgegrond)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"stuur bevele na die SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"verkry volle netwerktoegang"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"bestuur profiel- en toesteleienaars"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"verander WiMAX-status"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ontvang Android Straal-oordragstatus"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"roeteer media-uitvoer"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"lees installeersessies"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"versoek installeerpakkette"</string>
 </resources>
diff --git a/core/res/res/values-am-watch/strings.xml b/core/res/res/values-am-watch/strings.xml
index ebe6ae0..ee6ed57 100644
--- a/core/res/res/values-am-watch/strings.xml
+++ b/core/res/res/values-am-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g> መተግበሪያ ከ<xliff:g id="NUMBER_1">%2$d</xliff:g>።"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"አነፍናፊዎች"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"የእርስዎ እውቂያዎች ላይ ይድረሱባቸው"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"የዚህን ሰዓት መገኛ አካባቢ ይድረሱባቸው"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"የእርስዎን ቀን መቁጠሪያ ይድረሱበት"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"የኤስኤምኤስ መልዕክቶችን ይላኩና ይመልከቱ"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"በእርስዎ ሰዓት ላይ ፎቶዎችን፣ ሚዲያ እና ፋይሎችን ይድረሱባቸው"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ኦዲዮ ይቅዱ"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ስዕሎች ያንሱ እና ቪዲዮ ይቅረጹ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"የስልክ ጥሪዎች ያድርጉ እና ያስተዳድሩ"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ስለአስፈላጊ ምልክቶችዎ ያሉ የዳሳሽ ውሂብ ይድረሱ"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"የሁነታ አሞሌ ይሁን"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"የሰውነት ዳሳሾችን ይድረሱባቸው (እንደ የልብ ምት መከታተያዎች)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ትክክለኛ አካባቢ ይድረሱበት (በጂ ፒ ኤስ እና አውታረ መረብ ላይ የተመሠረተ)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ግምታዊ አካባቢን ይድረሱበት (በአውታረ መረብ ላይ የተመሰረተ)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ወደ ሲሙ ትዕዛዞችን ላክ"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ሙሉ የአውታረ መረብ መዳረሻ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"የመገለጫ እና የመሣሪያ ባለቤቶችን ያስተዳድሩ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"የWiMAX ሁኔታ ይለውጡ"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"የAndroid Beam ሽግግር ሁኔታን ይቀበሉ"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"የሚዲያ ውፅአት መንገድ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"የመጫን ክፍለ ጊዜዎችን አንብብ"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"የጭነት ጥቅሎችን ጠይቅ"</string>
 </resources>
diff --git a/core/res/res/values-ar-watch/strings.xml b/core/res/res/values-ar-watch/strings.xml
index 374b665..af6a164 100644
--- a/core/res/res/values-ar-watch/strings.xml
+++ b/core/res/res/values-ar-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"التطبيق <xliff:g id="NUMBER_0">%1$d</xliff:g> من <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"أجهزة الاستشعار"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"الوصول إلى جهات الاتصال التابعة لك"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"الوصول إلى موقع هذه الساعة"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"الوصول إلى تقويمك"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"‏إرسال رسائل قصيرة SMS وعرضها"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"الوصول إلى الصور والوسائط والملفات على ساعتك"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"تسجيل الصوت"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"التقاط صور وتسجيل فيديو"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"إجراء مكالمات هاتفية وإدارتها"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"الوصول إلى بيانات المستشعر حول علاماتك الحيوية"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"العمل كشريط للحالة"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"الوصول إلى أجهزة استشعار الجسم (مثل شاشات معدل ضربات القلب)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"‏الوصول إلى الموقع الدقيق (استنادًا إلى نظام تحديد المواقع العالمي \"GPS\" والشبكة)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"الوصول إلى الموقع التقريبي (استنادًا إلى الشبكة)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"‏إرسال أوامر إلى شريحة SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"حق الوصول بالكامل إلى الشبكة"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"إدارة المالكين لكل من الملف الشخصي والجهاز"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"‏تغيير حالة WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"‏تلقي حالة نقل شعاع Android"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"توجيه إخراج الوسائط"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"قراءة جلسات التثبيت"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"طلب حزم التثبيت"</string>
 </resources>
diff --git a/core/res/res/values-az-rAZ-watch/strings.xml b/core/res/res/values-az-rAZ-watch/strings.xml
index cdc6a3d..5a84880 100644
--- a/core/res/res/values-az-rAZ-watch/strings.xml
+++ b/core/res/res/values-az-rAZ-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Tətbiq <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorlar"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarınıza daxil olun"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"bu saatın məkanına giriş"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"təqvimə daxil olun"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"göndərin və SMS mesajlarına baxın"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Saatınızda foto, media və fayllara daxil olun"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"səsi qeydə alın"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"şəkil çəkin və video yazın"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon zəngləri edin və onları idarə edin"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"Həyati əlamətlər haqqında sensor dataya daxil olun"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"status paneli edin"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"bədən sensorlarına (ürək döyüntüsü monitorları kimi) giriş"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"dəqiq məkana (GPS və şəbəkə əsasında) giriş"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"təxmini məkana (şəbəkə əsaslı) giriş"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"əmrləri SIM\'ə göndərin"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"tam şəbəkə girişi var"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profil və cihaz sahiblərini idarə edin"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX vəziyyətini dəyişin"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam transfer statusunu əldə edin"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"media çıxışını yönləndirin"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"quraşdırma sessiyalarını oxuyun"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"paketləri quraşdırma sorğusu"</string>
 </resources>
diff --git a/core/res/res/values-bg-watch/strings.xml b/core/res/res/values-bg-watch/strings.xml
index a31f8d8..5eb2a02 100644
--- a/core/res/res/values-bg-watch/strings.xml
+++ b/core/res/res/values-bg-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Прилож. <xliff:g id="NUMBER_0">%1$d</xliff:g> от <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Сензори"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"достъп до контактите ви"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"достъп до местоположението на този часовник"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"достъп до календара ви"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"изпращане и преглед на SMS съобщения"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"достъп до снимките, мултимедията и файловете на часовника ви"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"записване на звук"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"правене на снимки и записване на видеоклипове"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"извършване и управление на телефонни обаждания"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"достъп до сензорните данни за жизнените ви показатели"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"изпълняване на ролята на лента на състоянието"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"достъп до сензорите за тяло (например пулсомери)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"достъп до точното местоположение (въз основа на GPS и мрежата)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"достъп до приблизителното местоположение (въз основа на мрежата)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"изпращане на команди до SIM картата"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"пълен достъп до мрежата"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"управление на собствениците на потребителските профили и устройствата"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"промяна на състоянието на WiMAX мрежата"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"получаване на състоянието на прехвърлянията чрез Android Лъч"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"маршрутизиране на извеждането на мултимедия"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"четене на сесии за инсталиране"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"заявка на пакети за инсталиране"</string>
 </resources>
diff --git a/core/res/res/values-bn-rBD-watch/strings.xml b/core/res/res/values-bn-rBD-watch/strings.xml
index 4ce6091..4ef2d6ea 100644
--- a/core/res/res/values-bn-rBD-watch/strings.xml
+++ b/core/res/res/values-bn-rBD-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>টির মধ্যে <xliff:g id="NUMBER_0">%1$d</xliff:g>টি অ্যাপ্লিকেশান"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"সেন্সরগুলি"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"আপনার পরিচিতিগুলিতে অ্যাক্সেস করুন"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"এই ঘড়ির অবস্থানে অ্যাক্সেস করুন"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"আপনার ক্যালেন্ডারে অ্যাক্সেস করুন"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS বার্তাগুলি পাঠান এবং দেখুন"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"আপনার দেখা ফটো, মিডিয়া এবং ফাইলগুলিতে অ্যাক্সেস করুন"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"অডিও রেকর্ড করুন"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ছবি তুলুন এবং ভিডিও রেকর্ড করুন"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ফোন কলগুলি করুন এবং পরিচালনা করুন"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"আপনার গুরুত্বপূর্ণ লক্ষণ এবং শারীরিক ক্রিয়াকলাপের সম্পর্কে তথ্য অ্যাক্সেস করুন"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"স্থিতি দন্ডে থাকুন"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"শরীরের সেন্সর (হার্ট রেট মনিটারের মত) অ্যাক্সেস করুন"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"সুনির্দিষ্ট অবস্থান (GPS এবং নেটওয়ার্ক-ভিত্তিক) অ্যাক্সেস করুন"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"আনুমানিক অবস্থান (নেটওয়ার্ক-ভিত্তিক) অ্যাক্সেস করুন"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM এ আদেশগুলি পাঠান"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"সম্পূর্ণ নেটওয়ার্ক অ্যাক্সেস রয়েছে"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"প্রোফাইল এবং ডিভাইস মালিকদের পরিচালনা করুন"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX এর স্থিতি পরিবর্তন করুন"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android বীম স্থানান্তর স্থিতি গ্রহণ করুন"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"মিডিয়া আউটপুট রুট করুন"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ইনস্টল সেশন পড়ুন"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"প্যাকেজগুলি ইনস্টল করার অনুরোধ"</string>
 </resources>
diff --git a/core/res/res/values-ca-watch/strings.xml b/core/res/res/values-ca-watch/strings.xml
index 8f626e5..231450f 100644
--- a/core/res/res/values-ca-watch/strings.xml
+++ b/core/res/res/values-ca-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplicació <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensors"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"accedir als contactes"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"accedir a la ubicació del rellotge"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"accedir al calendari"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar i llegir missatges SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accedir a les fotos, el contingut multimèdia i els fitxers del rellotge"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"enregistrar àudio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fer fotos i enregistrar vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fer i gestionar trucades telefòniques"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedir a les dades del sensor sobre els signes vitals"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"aparèixer a la barra d\'estat"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedir als sensors corporals (com ara monitors de freqüència cardíaca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"accedir a la ubicació precisa (basada en el GPS i la xarxa)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"accedir a la ubicació aproximada (basada en la xarxa)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar ordres a la SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"tenir accés complet a la xarxa"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gestionar els propietaris del perfil i del dispositiu"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"canviar l\'estat de WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"rebre l\'estat de la transferència d\'Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"indicar la sortida del fitxer multimèdia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"llegir les sessions d\'instal·lació"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"sol·licitar la instal·lació de paquets"</string>
 </resources>
diff --git a/core/res/res/values-cs-watch/strings.xml b/core/res/res/values-cs-watch/strings.xml
index 34f8864..229e1eb 100644
--- a/core/res/res/values-cs-watch/strings.xml
+++ b/core/res/res/values-cs-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikace <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzory"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"přístup ke kontaktům"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"přístup k poloze těchto hodinek"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"přístup ke kalendáři"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"odesílání a zobrazení zpráv SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"přístup k fotkám, médiím a souborům v hodinkách"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"nahrávání zvuku"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"pořizování fotografií a nahrávání videa"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"uskutečňování a správa telefonních hovorů"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"přístup k údajům senzorů vašich životních funkcí"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"vydávání se za stavový řádek"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"přístup k tělesným senzorům (jako jsou snímače tepu)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"přístup k přesné poloze (pomocí GPS a sítě)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"přístup k přibližné poloze (pomocí sítě)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"odesílání příkazů do SIM karty"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"úplný přístup k síti"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"správa vlastníků profilu a zařízení"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"změna stavu připojení WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"příjem stavu přenosů Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"směrování výstupu médií"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"čtení instalačních relací"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"žádost o instalaci balíčků"</string>
 </resources>
diff --git a/core/res/res/values-da-watch/strings.xml b/core/res/res/values-da-watch/strings.xml
index efc4cf2..094a50f 100644
--- a/core/res/res/values-da-watch/strings.xml
+++ b/core/res/res/values-da-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorer"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"få adgang til dine kontaktpersoner"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"få adgang til dette urs placering"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"få adgang til din kalender"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"sende og se sms-beskeder"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"få adgang til billeder, medier og filer på dit ur"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"optage lyd"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tage billeder og optage video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"foretage og administrere telefonopkald"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"få adgang til sensordata om dine livstegn"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"være statusbjælken"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"få adgang til kropssensorer (f.eks. pulsmålere)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"få adgang til nøjagtig placering (baseret på GPS og netværk)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"få adgang til omtrentlig placering (netværksbaseret)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"sende kommandoer til SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"få fuld netværksadgang"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"administrere profil- og enhedsejere"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"skifte WiMAX-tilstand"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"modtage status for Android Beam-overførsler"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"videreføre medieoutput"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"læse installationssessioner"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"anmode om installation af pakker"</string>
 </resources>
diff --git a/core/res/res/values-de-watch/strings.xml b/core/res/res/values-de-watch/strings.xml
index 99b3336..6f5941b 100644
--- a/core/res/res/values-de-watch/strings.xml
+++ b/core/res/res/values-de-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> von <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensoren"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"auf Kontakte zugreifen"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"auf den Standort dieser Smartwatch zugreifen"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"auf den Kalender zugreifen"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS senden und abrufen"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"auf Fotos, Medien und Dateien auf Ihrer Smartwatch zugreifen"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"Audio aufnehmen"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"Bilder und Videos aufnehmen"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"Telefonanrufe tätigen und verwalten"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"auf Sensordaten zu Ihren Vitaldaten zugreifen"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"Statusleiste darstellen"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"auf Körpersensoren wie beispielsweise Herzfrequenzmesser zugreifen"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"auf genauen Standort zugreifen (GPS- und netzwerkbasiert)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"auf den ungefähren Standort zugreifen (netzwerkbasiert)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"Befehle an die SIM senden"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"auf alle Netzwerke zugreifen"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"Profilinhaber und Geräteeigentümer verwalten"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX-Status ändern"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Status von Android Beam-Übertragungen erhalten"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"Medienausgabe umleiten"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"Installationssitzungen lesen"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"Installation von Paketen anfordern"</string>
 </resources>
diff --git a/core/res/res/values-el-watch/strings.xml b/core/res/res/values-el-watch/strings.xml
index c159d6f..83d9c3d 100644
--- a/core/res/res/values-el-watch/strings.xml
+++ b/core/res/res/values-el-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Εφαρμογή <xliff:g id="NUMBER_0">%1$d</xliff:g> από <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Αισθητήρες"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"πρόσβαση στις επαφές σας"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"πρόσβαση στην τοποθεσία αυτού του ρολογιού"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"πρόσβαση στο ημερολόγιό σας"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"αποστολή και προβολή μηνυμάτων SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"πρόσβαση στις φωτογραφίες, τα πολυμέσα και τα αρχεία στο ρολόι σας"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"εγγραφή ήχου"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"λήψη φωτογραφιών και εγγραφή βίντεο"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"πραγματοποίηση και διαχείριση τηλεφωνικών κλήσεων"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"πρόσβαση στα δεδομένα αισθητήρα σχετικά με τις ζωτικές ενδείξεις σας"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ορισμός ως γραμμής κατάστασης"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"πρόσβαση στους αισθητήρες λειτουργιών (π.χ. παρακολούθηση καρδιακού παλμού)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"πρόσβαση στην ακριβή τοποθεσία (με βάση το GPS και το δίκτυο)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"πρόσβαση στην τοποθεσία κατά προσέγγιση (με βάση το δίκτυο)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"στέλνει εντολές στην κάρτα SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"πλήρης πρόσβαση στο δίκτυο"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"διαχείριση προφίλ και κατόχων συσκευής"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"αλλαγή κατάστασης WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"λήψη κατάστασης μεταφοράς Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"δρομολόγηση εξόδου μέσων"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ανάγνωση περιόδων σύνδεσης εγκατάστασης"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"αίτημα εγκατάστασης πακέτων"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU-watch/strings.xml b/core/res/res/values-en-rAU-watch/strings.xml
index 6102d4e4..30357ce 100644
--- a/core/res/res/values-en-rAU-watch/strings.xml
+++ b/core/res/res/values-en-rAU-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensors"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"access your contacts"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"access this watch\'s location"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"access your calendar"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"send and view SMS messages"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"access photos, media and files on your watch"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"record audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"take pictures and record videos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"make and manage phone calls"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"access sensor data about your vital signs"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"be the status bar"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"access body sensors (like heart rate monitors)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"access precise location (GPS and network-based)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"access approximate location (network-based)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"send commands to the SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"have full network access"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"manage profile and device owners"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"change WiMAX state"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receive Android Beam transfer status"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"route media output"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"read install sessions"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"request install packages"</string>
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 28d8eb4..ea33448 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -223,7 +223,7 @@
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
diff --git a/core/res/res/values-en-rGB-watch/strings.xml b/core/res/res/values-en-rGB-watch/strings.xml
index 6102d4e4..30357ce 100644
--- a/core/res/res/values-en-rGB-watch/strings.xml
+++ b/core/res/res/values-en-rGB-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensors"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"access your contacts"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"access this watch\'s location"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"access your calendar"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"send and view SMS messages"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"access photos, media and files on your watch"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"record audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"take pictures and record videos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"make and manage phone calls"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"access sensor data about your vital signs"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"be the status bar"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"access body sensors (like heart rate monitors)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"access precise location (GPS and network-based)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"access approximate location (network-based)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"send commands to the SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"have full network access"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"manage profile and device owners"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"change WiMAX state"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receive Android Beam transfer status"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"route media output"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"read install sessions"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"request install packages"</string>
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 28d8eb4..ea33448 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -223,7 +223,7 @@
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
diff --git a/core/res/res/values-en-rIN-watch/strings.xml b/core/res/res/values-en-rIN-watch/strings.xml
index 6102d4e4..30357ce 100644
--- a/core/res/res/values-en-rIN-watch/strings.xml
+++ b/core/res/res/values-en-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> of <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensors"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"access your contacts"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"access this watch\'s location"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"access your calendar"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"send and view SMS messages"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"access photos, media and files on your watch"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"record audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"take pictures and record videos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"make and manage phone calls"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"access sensor data about your vital signs"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"be the status bar"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"access body sensors (like heart rate monitors)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"access precise location (GPS and network-based)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"access approximate location (network-based)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"send commands to the SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"have full network access"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"manage profile and device owners"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"change WiMAX state"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receive Android Beam transfer status"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"route media output"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"read install sessions"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"request install packages"</string>
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 28d8eb4..ea33448 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -223,7 +223,7 @@
     <string name="global_action_lockdown" msgid="8751542514724332873">"Lock now"</string>
     <string name="status_bar_notification_info_overflow" msgid="5301981741705354993">"999+"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
-    <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
+    <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="2804351898001038951">"Personal"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Work"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contacts"</string>
diff --git a/core/res/res/values-es-rUS-watch/strings.xml b/core/res/res/values-es-rUS-watch/strings.xml
index 76664ef..703cb32 100644
--- a/core/res/res/values-es-rUS-watch/strings.xml
+++ b/core/res/res/values-es-rUS-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceder a los contactos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"acceder a la ubicación de este reloj"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceder al calendario"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar y ver mensajes SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"acceder a las fotos, el contenido multimedia y los archivos del reloj"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"grabar audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tomar fotografías y grabar videos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"realizar y administrar llamadas telefónicas"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceder a los datos del sensor acerca de tus signos vitales"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"aparecer en la barra de estado"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"acceder a los sensores corporales (como los monitores de frecuencia cardíaca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"acceder a la ubicación precisa (según el GPS y la red)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"acceder a la ubicación aproximada (según la red)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos a la tarjeta SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"permitir acceso completo a la red"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"administrar perfiles de propietarios y propietario del dispositivo"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"cambiar estado de WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"recibir estado de transferencias de Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"dirigir salida de medios"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"leer sesiones de instalación"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar la instalación de paquetes"</string>
 </resources>
diff --git a/core/res/res/values-es-watch/strings.xml b/core/res/res/values-es-watch/strings.xml
index 002bfce..7eedf0c 100644
--- a/core/res/res/values-es-watch/strings.xml
+++ b/core/res/res/values-es-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceder a tus contactos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"acceder a la ubicación de este reloj"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceder a tu calendario"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar y ver mensajes SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"acceder a fotos, contenido multimedia y archivos en el reloj"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"grabar audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"hacer fotos y grabar vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"hacer y administrar llamadas de teléfono"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceder a datos del sensor sobre tus constantes vitales"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"aparecer en la barra de estado"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"acceder a sensores corporales (como monitores de frecuencia cardíaca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"acceder a tu ubicación precisa (basada en red y GPS)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"acceder a tu ubicación aproximada (basada en red)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos a la tarjeta SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"tener acceso completo a la red"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"administrar propietarios del perfil y del dispositivo"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"cambiar estado de WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"recibir estado de transferencias de Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"dirigir salida de medio"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"consultar sesiones de instalación"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar instalación de paquetes"</string>
 </resources>
diff --git a/core/res/res/values-et-rEE-watch/strings.xml b/core/res/res/values-et-rEE-watch/strings.xml
index a1d29a8..c554e38 100644
--- a/core/res/res/values-et-rEE-watch/strings.xml
+++ b/core/res/res/values-et-rEE-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Rakendus <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Andurid"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"juurdepääs kontaktidele"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"juurdepääs selle kella asukohale"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"juurdepääs kalendrile"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS-sõnumite saatmine ja vaatamine"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"juurdepääs teie kellas olevatele fotodele, meediale ja failidele"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"heli salvestamine"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"pildistamine ja video salvestamine"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"helistamine ja telefonikõnede haldamine"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"juurdepääs anduri andmetele teie eluliste näitajate kohta"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"olekuribana kuvamine"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"juurdepääs kehaanduritele (nt pulsilugeja)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"juurdepääs täpsele asukohale (GPS-i ja võrgupõhine)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"juurdepääs ligikaudsele asukohale (võrgupõhine)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM-kaardile käskluste saatmine"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"täielik juurdepääs võrgule"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profiilide ja seadmeomanike haldamine"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX-i oleku muutmine"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beami ülekande oleku vastuvõtmine"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"meediaväljundi marsruutimine"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"installiseansside lugemine"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"installipakettide taotlemine"</string>
 </resources>
diff --git a/core/res/res/values-eu-rES-watch/strings.xml b/core/res/res/values-eu-rES-watch/strings.xml
index aa67602..0fca702 100644
--- a/core/res/res/values-eu-rES-watch/strings.xml
+++ b/core/res/res/values-eu-rES-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> aplikaz."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sentsoreak"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"Atzitu kontaktuak"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"Atzitu erlojuaren kokapena"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"Atzitu egutegia"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"Bidali eta ikusi SMS mezuak"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Atzitu erlojuko argazkiak, multimedia-edukia eta fitxategiak"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"Grabatu audioa"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"Atera argazkiak eta grabatu bideoak"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"Egin eta kudeatu telefono-deiak"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"Atzitu bizi-konstanteei buruzko sentsore-datuak"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"Bihurtu egoera-barra"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"Atzitu gorputzaren sentsoreak (adibidez, bihotz-erritmoaren monitoreak)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"Atzitu kokapen zehatza (GPS sisteman eta sarean oinarrituta)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"Atzitu gutxi gorabeherako kokapena (sarean oinarrituta)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"Bidali aginduak SIM txartelera"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"Izan sarerako sarbide osoa"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"Kudeatu profilen eta gailuen jabeak"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"Aldatu WiMAX egoera"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Jaso Android Beam transferentzien egoera"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"Bideratu multimedia-irteera"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"Irakurri instalazio-saioak"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"Eskatu instalazio-paketeak"</string>
 </resources>
diff --git a/core/res/res/values-fa-watch/strings.xml b/core/res/res/values-fa-watch/strings.xml
index 243ccad..5fe8359 100644
--- a/core/res/res/values-fa-watch/strings.xml
+++ b/core/res/res/values-fa-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"برنامه <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"حسگرها"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"دسترسی به مخاطبین شما"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"دسترسی به مکان این ساعت"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"دسترسی به تقویم شما"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"ارسال و مشاهده پیامک‌ها"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"دسترسی به عکس‌، رسانه‌ و فایل‌های روی ساعتتان"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ضبط صدا"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"عکس گرفتن و فیلم‌برداری"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"برقراری و مدیریت تماس‌های تلفنی"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"دسترسی به داده‌های حسگر در رابطه با علائم حیاتی شما"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"نوار وضعیت باشد"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"دسترسی به حسگرهای بدن (مانند مانیتورهای ضربان قلب)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"‏دسترسی به مکان دقیق (مبتنی بر GPS و شبکه)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"دسترسی به مکان تقریبی (مبتنی بر شبکه)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ارسال فرمان‌ها به سیم کارت"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"داشتن دسترسی کامل به شبکه"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"مدیریت نمایه و مالکان دستگاه"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"‏تغییر وضعیت WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"‏دریافت وضعیت انتقال پرتوی Android"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"تعیین مسیر خروجی رسانه"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"خواندن جلسات نصب"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"درخواست نصب بسته‌بندی"</string>
 </resources>
diff --git a/core/res/res/values-fi-watch/strings.xml b/core/res/res/values-fi-watch/strings.xml
index abe5ebb..662e0ab 100644
--- a/core/res/res/values-fi-watch/strings.xml
+++ b/core/res/res/values-fi-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Sovellus <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Anturit"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"käyttää yhteystietoja"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"käyttää tämän kellon sijaintia"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"käyttää kalenteria"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"lähettää ja tarkastella tekstiviestejä"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"käyttää kellosi kuvia, mediaa ja tiedostoja"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"tallentaa ääntä"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ottaa kuvia ja videoita"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"soittaa ja hallinnoida puheluita"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"käyttää anturitietoja elintoiminnoistasi"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"sijaita tilapalkissa"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"käyttää kehon antureita (kuten sykemittareita)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"käyttää tarkkaa sijaintia (GPS- ja verkkopohjainen)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"käyttää likimääräistä sijaintia (verkkopohjainen)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"lähettää komentoja SIM-kortille"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"saada täydet verkon käyttöoikeudet"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"hallinnoida laitteen ja profiilien omistajia"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"vaihtaa WiMAX-verkon tilaa"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"vastaanottaa Android Beam -siirron tilatietoja"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"reitittää mediaa"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"lukea asennusistuntoja"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"pyytää pakettien asennusta"</string>
 </resources>
diff --git a/core/res/res/values-fr-rCA-watch/strings.xml b/core/res/res/values-fr-rCA-watch/strings.xml
index 197b18a..8f2e683 100644
--- a/core/res/res/values-fr-rCA-watch/strings.xml
+++ b/core/res/res/values-fr-rCA-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Appli <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Capteurs"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"accéder à vos contacts"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"accéder à la position de cette montre"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"accéder à votre agenda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"envoyer et afficher des messages texte"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accéder à des photos, à des contenus multimédias et à des fichiers sur votre montre"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"enregistrer des fichiers audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"prendre des photos et filmer des vidéos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"faire et gérer des appels téléphoniques"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accéder aux données des capteurs sur vos signes vitaux"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"faire office de barre d\'état"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accéder aux capteurs corporels (comme les moniteurs de fréquence cardiaque)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"accéder à votre position précise (GPS et réseau)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"accéder à votre position approximative (réseau)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"envoyer des commandes à la carte SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"bénéficier d\'un accès complet au réseau"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gérer les propriétaires des profils et de l\'appareil"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"modifier l\'état du WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"recevoir des données sur l\'état du transfert Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"diriger la sortie multimédia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"accéder aux sessions d\'installation"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"demander l\'installation de paquets"</string>
 </resources>
diff --git a/core/res/res/values-fr-watch/strings.xml b/core/res/res/values-fr-watch/strings.xml
index b853188..21bf8a6 100644
--- a/core/res/res/values-fr-watch/strings.xml
+++ b/core/res/res/values-fr-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Appli <xliff:g id="NUMBER_0">%1$d</xliff:g> sur <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Capteurs"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"accéder à vos contacts"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"accéder à la position de cette montre"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"accéder à votre agenda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"envoyer et consulter des SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accéder à des photos, à des contenus multimédias et à des fichiers sur votre montres"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"enregistrer des fichiers audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"prendre des photos et enregistrer des vidéos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"effectuer et gérer des appels téléphoniques"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accéder aux données des capteurs relatives à vos signes vitaux"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"remplacer la barre d\'état"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accéder aux capteurs corporels (tels que les cardiofréquencemètres)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"accéder à votre position précise (GPS et réseau)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"accéder à votre position approximative (selon le réseau)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"envoyer des commandes à la carte SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"bénéficier d\'un accès complet au réseau"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gérer les propriétaires des profils et de l\'appareil"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"modifier l\'état du WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"recevoir des informations sur l\'état du transfert Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"diriger la sortie multimédia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"accéder aux sessions d\'installation"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"demander l\'installation de packages"</string>
 </resources>
diff --git a/core/res/res/values-gl-rES-watch/strings.xml b/core/res/res/values-gl-rES-watch/strings.xml
index 002bfce..95d6400 100644
--- a/core/res/res/values-gl-rES-watch/strings.xml
+++ b/core/res/res/values-gl-rES-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplicación <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceder aos contactos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"acceder á localización deste reloxo"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceder ao calendario"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"envíar e consultar mensaxes de SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"acceder ás fotos, ao contido multimedia e aos ficheiros do teu reloxo"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"gravar audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tirar fotos e gravar vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"facer e xestionar chamadas telefónicas"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceder aos datos do sensor sobre as túas constantes vitais"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"actuar como a barra de estado"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"acceder a sensores do corpo (como monitores de ritmo cardíaco)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"acceder á localización precisa (baseada no GPS e na rede)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"acceder á localización aproximada (baseada na rede)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos á SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ter acceso completo á rede"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"xestionar propietarios do perfil e do dispositivo"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"cambiar estado de WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"recibir o estado das transferencias de Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"dirixir saída multimedia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ler sesións de instalación"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar instalación de paquetes"</string>
 </resources>
diff --git a/core/res/res/values-gu-rIN-watch/strings.xml b/core/res/res/values-gu-rIN-watch/strings.xml
index f607966..af1b068 100644
--- a/core/res/res/values-gu-rIN-watch/strings.xml
+++ b/core/res/res/values-gu-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> માંથી <xliff:g id="NUMBER_0">%1$d</xliff:g> એપ્લિકેશન."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"સેન્સર્સ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"આ ઘડિયાળના સ્થાનને ઍક્સેસ કરો"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"તમારા કેલેન્ડરને ઍક્સેસ કરો"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS સંદેશા મોકલો અને જુઓ"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"તમારી ઘડિયાળ પર ફોટા, મીડિયા અને ફાઇલો ઍક્સેસ કરો"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ઑડિઓ રેકોર્ડ કરો"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ચિત્રો લો અને વિડિઓ રેકોર્ડ કરો"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ફોન કૉલ્સ કરો તથા સંચાલિત કરો"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"તમારા મહત્વપૂર્ણ ચિહ્નો વિશે સેન્સર ડેટા ઍક્સેસ કરો"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"સ્થિતિ બાર થાઓ"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"બૉડી સેન્સર્સ ઍક્સેસ કરો (જેમ કે હાર્ટ રેટ મૉનિટર્સ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"નિશ્ચિત સ્થાન ઍક્સેસ કરો (GPS અને નેટવર્ક-આધારિત)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"અંદાજિત સ્થાન (નેટવર્ક-આધારિત)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM ને આદેશો મોકલો"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"પૂર્ણ નેટવર્ક ઍક્સેસ મેળવો"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"પ્રોફાઇલ અને ઉપકરણ માલિકોને સંચાલિત કરો"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX સ્થિતિ બદલો"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android બીમ ટ્રાન્સફર સ્થિતિ પ્રાપ્ત કરો"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"મીડિયા આઉટપુટ રૂટ કરો"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ઇન્સ્ટોલ સત્રો વાંચો"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"પૅકેજેસ ઇન્સ્ટોલ કરવાની વિનંતી કરો"</string>
 </resources>
diff --git a/core/res/res/values-hi-watch/strings.xml b/core/res/res/values-hi-watch/strings.xml
index ead4d60..afed795 100644
--- a/core/res/res/values-hi-watch/strings.xml
+++ b/core/res/res/values-hi-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> में से <xliff:g id="NUMBER_0">%1$d</xliff:g> ऐप."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"संवेदक"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"अपने संपर्कों को ऐक्सेस करें"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"इस घड़ी के स्थान को ऐक्सेस करें"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"अपने कैलेंडर को ऐक्सेस करें"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS संदेश भेजें और देखें"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"अपनी घड़ी पर फ़ोटो, मीडिया और फ़ाइलें ऐक्सेस करें"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ऑडियो रिकॉर्ड करें"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"चित्र लें और वीडियो रिकॉर्ड करें"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"फ़ोन कॉल करें और प्रबंधित करें"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"अपने महत्वपूर्ण संकेतों के बारे में सेंसर डेटा को ऐक्सेस करें"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"स्‍थिति बार होने दें"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"शरीर संवेदक ऐक्सेस करें (जैसे हृदय गति मॉनीटर)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"सटीक स्थान ऐक्सेस करें (GPS और नेटवर्क-आधारित)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"अनुमानित स्थान ऐक्सेस करें (नेटवर्क-आधारित)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM पर आदेश भेजें"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"पूर्ण नेटवर्क ऐक्सेस पाएं"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"प्रोफ़ाइल और डिवाइस स्‍वामियों को प्रबंधित करें"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX स्‍थिति बदलें"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam ट्रांसफर स्थिति प्राप्त करें"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"मीडिया आउटपुट को रूट करें"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"इंस्टॉल सत्रों को पढ़ें"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"पैकेज इंस्टॉल करने का अनुरोध करें"</string>
 </resources>
diff --git a/core/res/res/values-hr-watch/strings.xml b/core/res/res/values-hr-watch/strings.xml
index 7e65f07..dda3cb2 100644
--- a/core/res/res/values-hr-watch/strings.xml
+++ b/core/res/res/values-hr-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikacija <xliff:g id="NUMBER_0">%1$d</xliff:g> od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"pristupati vašim kontaktima"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"pristupati lokaciji ovog sata"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"pristupati kalendaru"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"slati i pregledavati SMS poruke"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"pristupati fotografijama, medijima i datotekama na vašem satu"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"snimati zvuk"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"snimati fotografije i videozapise"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"uspostavljati telefonske pozive i upravljati njima"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"pristupati podacima senzora o vašim vitalnim znakovima"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"biti traka statusa"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"pristupati biometrijskim senzorima (kao što su monitori otkucaja srca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"pristupati preciznoj lokaciji (na temelju GPS-a i mreža)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"pristupati približnoj lokaciji (na temelju mreža)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"slati naredbe SIM-u"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"imati puni mrežni pristup"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"upravljati vlasnicima profila i uređaja"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"promijeniti stanje WiMAX-a"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"primati status prijenosa Android Beama"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"usmjeravati medijski izlaz"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"čitati sesije instaliranja"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"zahtijevati instaliranje paketa"</string>
 </resources>
diff --git a/core/res/res/values-hu-watch/strings.xml b/core/res/res/values-hu-watch/strings.xml
index aa72468..7c45326 100644
--- a/core/res/res/values-hu-watch/strings.xml
+++ b/core/res/res/values-hu-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>. alkalmazás"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Érzékelők"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"hozzáférés a névjegyekhez"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"hozzáférés ennek az órának a helyadataihoz"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"hozzáférés a naptárhoz"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS-ek küldése és megtekintése"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"hozzáférés az órán lévő fotókhoz, médiatartalmakhoz és fájlokhoz"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"hanganyag rögzítése"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotók és videók készítése"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefonhívások kezdeményezése és kezelése"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"hozzáférés az érzékelők által mért, életjelekkel kapcsolatos adatokhoz"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"az állapotsor szerepének átvétele"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"hozzáférés a testérzékelőkhöz (például pulzusmérők)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"hozzáférés a pontos (GPS- és hálózatalapú) helyadatokhoz"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"hozzáférés a hozzávetőleges (hálózatalapú) helyadatokhoz"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"parancsok küldése a SIM kártyára"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"teljes hálózati hozzáférés"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profil és eszköztulajdonosok kezelése"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX-állapot módosítása"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"android Beam-átviteli állapot fogadása"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"médiafájlok kimenetének irányítása"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"telepítési munkamenetek olvasása"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"telepítőcsomagok kérése"</string>
 </resources>
diff --git a/core/res/res/values-hy-rAM-watch/strings.xml b/core/res/res/values-hy-rAM-watch/strings.xml
index 28617cb..9bff6ad 100644
--- a/core/res/res/values-hy-rAM-watch/strings.xml
+++ b/core/res/res/values-hy-rAM-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Հավելված <xliff:g id="NUMBER_0">%1$d</xliff:g>՝ <xliff:g id="NUMBER_1">%2$d</xliff:g>-ից:"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Սենսորներ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"օգտագործել ձեր կոնտակտները"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"օգտագործել այս ժամացույցի տեղադրությունը"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"օգտագործել ձեր օրացույցը"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"ուղարկել և դիտել SMS հաղորդագրությունները"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"օգտագործել լուսանկարները, մեդիա ֆայլերը և ձեր ժամացույցում պահվող այլ ֆայլերը"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ձայնագրել"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"լուսանկարել և տեսագրել"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"կատարել հեռախոսազանգեր և կառավարել դրանք"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"օգտագործել ձեր հիմնական ֆիզիոլոգիական ցուցանիշների վերաբերյալ սենսորի տվյալները"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"լինել կարգավիճակի գոտի"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"օգտագործել մարմնի սենսորները (օրինակ` սրտի կծկումների հաճախականության չափիչ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"օգտագործել ճշգրիտ տեղադրությունը (GPS և ցանցային)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"օգտագործել մոտավոր տեղադրությունը (ցանցային)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ուղարկել հրամաններ SIM քարտին"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ունենալ ամբողջական ցանցային մուտք"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"կառավարել պրոֆիլները և սարքի սեփականատերերին"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"փոխել WiMAX-ի կարգավիճակը"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ստանալ Android Beam-ով փոխանցման կարգավիճակը"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"երթուղել մեդիա արտածումը"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"կարդալ տեղադրման աշխատաշրջանները"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"պահանջել տեղադրման փաթեթներ"</string>
 </resources>
diff --git a/core/res/res/values-in-watch/strings.xml b/core/res/res/values-in-watch/strings.xml
index b0b22e7..ef88a11 100644
--- a/core/res/res/values-in-watch/strings.xml
+++ b/core/res/res/values-in-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikasi <xliff:g id="NUMBER_0">%1$d</xliff:g> dari <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensor"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"akses kontak"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"akses lokasi jam tangan ini"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"akses kalender"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"kirim dan lihat pesan SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"akses foto, media, dan file di jam tangan"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"rekam audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ambil gambar dan rekam video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"lakukan dan kelola panggilan telepon"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"akses data sensor tentang tanda-tanda vital"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"jadikan bilah status"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"akses sensor tubuh (misalnya, monitor detak jantung)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"akses lokasi akurat (berbasis jaringan dan GPS)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"akses perkiraan lokasi (berbasis jaringan)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"kirimkan perintah ke SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"dapatkan akses jaringan penuh"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"kelola pemilik profil dan perangkat"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"ubah status WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"terima status transfer Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"tentukan rute keluaran media"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"baca sesi pemasangan"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"minta pasang paket"</string>
 </resources>
diff --git a/core/res/res/values-is-rIS-watch/strings.xml b/core/res/res/values-is-rIS-watch/strings.xml
index ab82c1c..d512b6e 100644
--- a/core/res/res/values-is-rIS-watch/strings.xml
+++ b/core/res/res/values-is-rIS-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Forrit <xliff:g id="NUMBER_0">%1$d</xliff:g> af <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Skynjarar"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"fá aðgang að tengiliðunum þínum"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"fá aðgang að staðsetningu þessa úrs"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"fá aðgang að dagatalinu þínu"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"senda og skoða SMS-skilaboð"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"fá aðgang að myndum, efni og skrám í úrinu þínu"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"taka upp hljóð"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"taka myndir og myndskeið"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"hringja og stjórna símtölum"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"fá aðgang að skynjaragögnum yfir lífsmörk þín"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"vera stöðustikan"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"fá aðgang að líkamsskynjurum (s.s. hjartsláttarmælum)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"fá aðgang að nákvæmri staðsetningu (frá GPS og símkerfi)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"fá aðgang að áætlaðri staðsetningu (frá símkerfi)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"senda skipanir til SIM-kortsins"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"hafa fullan netaðgang"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"stjórna eigendum sniða og tækja"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"breyta stöðu WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"fá flutningsstöðu Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"beina margmiðlunarúttaki"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"lesa uppsetningarlotur"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"fara fram á uppsetningu pakka"</string>
 </resources>
diff --git a/core/res/res/values-it-watch/strings.xml b/core/res/res/values-it-watch/strings.xml
index 111c2a2..c348e48 100644
--- a/core/res/res/values-it-watch/strings.xml
+++ b/core/res/res/values-it-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> di <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensori"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"accedere ai contatti"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"accedere alla posizione dell\'orologio"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"accedere al calendario"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"inviare e visualizzare SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accedere a foto, contenuti multimediali e file sull\'orologio"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"registrare audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"scattare foto e registrare video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fare e gestire telefonate"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"avere la funzione di barra di stato"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedere ai sensori (come il cardiofrequenzimetro)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"accedere alla posizione esatta (basata su GPS e rete)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"accedere alla posizione approssimativa (basata sulla rete)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"inviare comandi alla SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"avere accesso completo alla rete"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gestire proprietari di dispositivi e profili"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"modificare lo stato WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ricevere lo stato dei trasferimenti Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"indirizzare l\'output dei contenuti multimediali"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"leggere sessioni di installazione"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"richiedere pacchetti di installazione"</string>
 </resources>
diff --git a/core/res/res/values-iw-watch/strings.xml b/core/res/res/values-iw-watch/strings.xml
index d0b4943..1e4bad4 100644
--- a/core/res/res/values-iw-watch/strings.xml
+++ b/core/res/res/values-iw-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"אפליקציה <xliff:g id="NUMBER_0">%1$d</xliff:g> מתוך <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"חיישנים"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"גישה אל אנשי הקשר"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"גישה אל מיקום השעון הזה"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"גישה אל היומן"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"‏שליחה והצגה של הודעות SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"גישה אל תמונות, מדיה וקבצים בשעון שלך"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"הקלטת אודיו"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"צילום תמונות והקלטת סרטונים"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"התקשרות וניהול של שיחות טלפון"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"גישה אל נתוני חיישנים של הסימנים החיוניים שלך"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"להיות שורת מצב"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"גישה אל חיישני גוף (כמו מוניטורים עבור קצב לב)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"‏גישה אל מיקום מדויק (מבוסס GPS ורשת)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"גישה אל מיקום משוער (מבוסס רשת)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"‏שלח פקודות אל ה-SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"קבלת גישת רשת מלאה"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ניהול בעלים של פרופיל ומכשיר"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"‏שנה את מצב WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"‏קבלת סטטוס העברה של Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"ניתוב פלט מדיה"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"קריאת פעילות התקנה"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"בקשה להתקנת חבילות"</string>
 </resources>
diff --git a/core/res/res/values-ja-watch/strings.xml b/core/res/res/values-ja-watch/strings.xml
index ec1257ef..3248041 100644
--- a/core/res/res/values-ja-watch/strings.xml
+++ b/core/res/res/values-ja-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"アプリ<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"センサー"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"連絡先へのアクセス"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"この時計の位置情報へのアクセス"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"カレンダーへのアクセス"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMSメッセージの送信と表示"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"時計上の写真、メディア、ファイルへのアクセス"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"録音"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"写真の撮影と動画の記録"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"通話の発信と管理"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"バイタルサインに関するセンサーデータへのアクセス"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ステータスバーへの表示"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ボディーセンサー(心拍数モニターなど)へのアクセス"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"正確な位置情報(GPSとネットワーク基地局)へのアクセス"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"おおよその位置情報(ネットワーク基地局)へのアクセス"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIMへのコマンド送信"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ネットワークへのフルアクセス"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロフィールの所有者と端末の所有者の管理"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX状態の変更"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Androidビーム転送のステータスの受信"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"メディア出力のルーティング"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"インストールセッションの読み取り"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"インストールパッケージのリクエスト"</string>
 </resources>
diff --git a/core/res/res/values-ka-rGE-watch/strings.xml b/core/res/res/values-ka-rGE-watch/strings.xml
index 5aa9aaf..9e2ca1f 100644
--- a/core/res/res/values-ka-rGE-watch/strings.xml
+++ b/core/res/res/values-ka-rGE-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"აპი <xliff:g id="NUMBER_0">%1$d</xliff:g>, სულ <xliff:g id="NUMBER_1">%2$d</xliff:g>-დან."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"სენსორები"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"თქვენს კონტაქტებზე წვდომა"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ამ ნახვის მდებარეობაზე წვდომა"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"თქვენს კალენდარზე წვდომა"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS შეტყობინებების გაგზავნა და ნახვა"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"თქვენს სანახავ ფოტოებზე, მედიაზე და ფაილებზე წვდომა"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"აუდიოს ჩაწერა"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ფოტოებისა და ვიდეოების გადაღება"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"სატელეფონო ზარების გაშვება და მართვა"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"თქვენი სასიცოცხლო ნიშნების შესახებ სენეორის მონაცემებზე წვდომა"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"სტატუსის ზოლის ჩანაცვლება"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"სხეულის სენსორებზე (როგორიცაა გულისცემის სიხშირე) წვდომა"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ზუსტ მდებარეობაზე წვდომა (GPS-ის და ქსელის მიხედვით)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"მიახლოებით მდებარეობაზე წვდომა (ქსელის მიხედვით)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ბრძანებების SIM-ზე გაგზავნა"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"მთელ ქსელზე წვდომის მიღება"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"პროფილისა და მოწყობილობის მფლობელების მართვა"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX-ის მდგომარეობის შეცვლა"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android სხივით გადაცემის სტატუსის მიღება"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"მედიის მონაცემების მარშრუტიზაცია"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ინსტალაციის სესიების წაკითხვა"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"პაკეტების ინსტალაციის მოთხოვნა"</string>
 </resources>
diff --git a/core/res/res/values-kk-rKZ-watch/strings.xml b/core/res/res/values-kk-rKZ-watch/strings.xml
index e913230..8c41688 100644
--- a/core/res/res/values-kk-rKZ-watch/strings.xml
+++ b/core/res/res/values-kk-rKZ-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g> бағдарлама."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Сенсорлар"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"контактілерге қатынасу"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"осы сағаттың орнына қатынасу"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"күнтізбеге қатынасу"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS хабарларын жіберу және көру"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"сағаттағы фотосуреттерге, медиафайлдарға және файлдарға қатынасу"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"аудио жазу"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"суреттер түсіру және бейне жазу"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"қоңырау шалу және телефон қоңырауларын басқару"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ағза күйінің көрсеткіштері туралы сенсор деректеріне қатынасу"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"күй жолағы болу"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"дене датчиктеріне (мысалы, жүрек соғу жиілігінің мониторларына) қатынасу"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"дәл орынға қатынасу (GPS және желіге негізделген)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"шамамен алған орынға қатынасу (желі негізінде)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM картасына пәрмендер жіберу"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"желіге толық қатынасы бар"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"профиль және құрылғы иелерін басқару"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX күйін өзгерту"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam тасымалдау күйін алу"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"медиа шығысын бағыттау"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"орнату сеанстарын оқу"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"орнату бумаларын сұрау"</string>
 </resources>
diff --git a/core/res/res/values-km-rKH-watch/strings.xml b/core/res/res/values-km-rKH-watch/strings.xml
index 01731f3..5c1bf8a 100644
--- a/core/res/res/values-km-rKH-watch/strings.xml
+++ b/core/res/res/values-km-rKH-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"កម្មវិធី <xliff:g id="NUMBER_0">%1$d</xliff:g> នៃ <xliff:g id="NUMBER_1">%2$d</xliff:g>។"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"ឧបករណ៍ចាប់សញ្ញា"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"ចូលដំណើរការទំនាក់ទំនងរបស់អ្នក"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ចូលដំណើរការទីតាំងនាឡិកាដៃនេះ"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"ចូលដំណើរការប្រិតិទិនរបស់អ្នក"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"ផ្ញើ និងមើលសារ SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"ចូលដំណើរការរូបថត មេឌៀ និងឯកសារនៅលើនាឡិកាដៃរបស់អ្នក។"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ថតសំឡេង"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ថតរូប និងថតវីដេអូ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ហៅទូរស័ព្ទ និងគ្រប់គ្រងការហៅទូរស័ព្ទ"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ចូលដំណើរការទិន្នន័យឧបករណ៍ចាប់សញ្ញាអំពីស្ថានភាពសុខភាពរបស់អ្នក"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ធ្វើជារបារស្ថានភាព"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ចូលដំណើរការឧបករណ៍ចាប់សញ្ញារាងកាយ (ដូចជាម៉ាស៊ីនវាស់ចង្វាក់បេះដូង)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ចូលដំណើរការទីតាំងច្បាស់លាស់ (ផ្អែកលើបណ្តាញ និង GPS)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ចូលដំណើរការទីតាំងប្រហាក់ប្រហែល (ផ្អែកលើបណ្តាញ)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ផ្ញើពាក្យបញ្ជាទៅស៊ីមកាត"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"មានការចូលដំណើរការបណ្ដាញពេញលេញ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"គ្រប់គ្រងម្ចាស់ឧបករណ៍ និងប្រវត្តិរូប"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"ប្ដូរស្ថានភាព WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ទទួលបានស្ថានភាពផ្ទេរ Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"នាំផ្លូវលទ្ធផលមេឌៀ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"អានវេនដំឡើង"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ស្នើសុំកញ្ចប់ដំឡើង"</string>
 </resources>
diff --git a/core/res/res/values-kn-rIN-watch/strings.xml b/core/res/res/values-kn-rIN-watch/strings.xml
index ea010b3..def2130 100644
--- a/core/res/res/values-kn-rIN-watch/strings.xml
+++ b/core/res/res/values-kn-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="NUMBER_0">%1$d</xliff:g> ಅಪ್ಲಿಕೇಶನ್."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"ಸೆನ್ಸರ್‌ಗಳು"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ಈ ಗಡಿಯಾರದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಿ ಮತ್ತು ವೀಕ್ಷಿಸಿ"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"ನಿಮ್ಮ ಗಡಿಯಾರದಲ್ಲಿನ ಫೋಟೋಗಳು, ಮಾಧ್ಯಮ ಮತ್ತು ಫೈಲ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ಆಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ಚಿತ್ರಗಳನ್ನು ತೆಗೆಯಿರಿ ಹಾಗೂ ವೀಡಿಯೊ ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ಫೋನ್ ಕರೆಗಳನ್ನು ಮಾಡಿ ಹಾಗೂ ನಿರ್ವಹಿಸಿ"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ನಿಮ್ಮ ಮುಖ್ಯ ಲಕ್ಷಣಗಳ ಕುರಿತು ಸೆನ್ಸರ್ ಡೇಟಾವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಾಗಿರಲು"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ದೇಹ ಸೆನ್ಸರ್‌ಗಳನ್ನು ಪ್ರವೇಶಿಸಿ (ಹೃದಯದ ಬಡಿತ ಮಾನಿಟರ್‌ಗಳಂತಹ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ನಿಖರ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ (GPS ಮತ್ತು ನೆಟ್‍ವರ್ಕ್-ಆಧಾರಿತ)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ಅಂದಾಜು ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ (ನೆಟ್‌ವರ್ಕ್-ಆಧಾರಿತ)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ಸಿಮ್‌ಗೆ ಆಜ್ಞೆಗಳನ್ನು ಕಳುಹಿಸಿ"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ಪೂರ್ಣ ನೆಟ್‌ವರ್ಕ್ ಪ್ರವೇಶವನ್ನು ಹೊಂದಿರಿ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ಪ್ರೊಫೈಲ್ ಮತ್ತು ಸಾಧನ ಮಾಲೀಕರನ್ನು ನಿರ್ವಹಿಸಿ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX ಸ್ಥಿತಿಯನ್ನು ಬದಲಿಸಿ"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android ಬೀಮ್ ವರ್ಗಾವಣೆ ಸ್ಥಿತಿ ಸ್ವೀಕರಿಸಿ"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"ಮಾಧ್ಯಮ ಔಟ್‍ಪುಟ್ ಅನ್ನು ರೂಟ್ ಮಾಡಿ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ಸ್ಥಾಪನೆ ಸೆಷನ್‌ಗಳನ್ನು ಓದಿ"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ಸ್ಥಾಪನೆ ಪ್ಯಾಕೇಜ್‌ಗಳನ್ನು ವಿನಂತಿಸಿ"</string>
 </resources>
diff --git a/core/res/res/values-ko-watch/strings.xml b/core/res/res/values-ko-watch/strings.xml
index 985f401..8602c7e 100644
--- a/core/res/res/values-ko-watch/strings.xml
+++ b/core/res/res/values-ko-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"앱 <xliff:g id="NUMBER_1">%2$d</xliff:g>개 중 <xliff:g id="NUMBER_0">%1$d</xliff:g>개"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"센서"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"주소록에 액세스"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"이 시계 위치에 액세스"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"캘린더에 액세스"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS 메시지 보내기 및 보기"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"시계의 사진, 미디어, 파일에 액세스"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"오디오 녹음"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"사진 찍기 및 동영상 녹화"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"전화 걸기 및 관리"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"생체 신호에 관한 센서 데이터에 액세스"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"상태 표시줄에 위치"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"신체 센서(예: 심박수 모니터)에 액세스"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"정확한 위치(GPS 및 네트워크 기반)에 액세스"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"대략적인 위치(네트워크 기반)에 액세스"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM에 명령어 보내기"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"전체 네트워크 액세스 권한 보유"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"프로필 및 기기 소유자 관리"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX 상태 변경"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam 전송 상태 수신"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"미디어 출력 연결"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"설치 세션 읽기"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"패키지 설치 요청"</string>
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 1844214..f5a6fa4 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -431,7 +431,7 @@
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"지문 인식 작업이 취소되었습니다."</string>
     <string name="fingerprint_error_lockout" msgid="5536934748136933450">"시도 횟수가 너무 많습니다. 나중에 다시 시도하세요."</string>
     <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"다시 시도해 보세요."</string>
-    <string name="fingerprint_name_template" msgid="5870957565512716938">"<xliff:g id="FINGERID">%d</xliff:g>번째 손가락"</string>
+    <string name="fingerprint_name_template" msgid="5870957565512716938">"손가락 <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"지문 아이콘"</string>
diff --git a/core/res/res/values-ky-rKG-watch/strings.xml b/core/res/res/values-ky-rKG-watch/strings.xml
index 3c708961..2fb9047 100644
--- a/core/res/res/values-ky-rKG-watch/strings.xml
+++ b/core/res/res/values-ky-rKG-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> ичинен <xliff:g id="NUMBER_0">%1$d</xliff:g> колднм."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Сенсорлор"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"байланыштарыңызга уруксат"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"бул сааттын жайгашкан жерине уруксат"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"жылнаамаңызды пайдалануу"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS билдирүүлөрдү жөнөтүү жана көрсөтүү"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"саатыңыздагы сүрөттөр, медиа жана файлдарга уруксат"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"аудио жаздыруу"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"сүрөт тартуу жана видео жаздыруу"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"телефон чалуу жана аларды башкаруу"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"организмдин абалына көз салган сенсордун дайындарына мүмкүнчүлүк алуу"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"абал тилкесинин милдетин аткаруу"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"дене-бой сенсорлоруна (жүрөктүн кагышын өлчөгүчтөр сыяктуу) уруксат"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"так аныкталган жайгашкан жерге (GPS жана тармактын негизинде) уруксат"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"болжолдуу жайгашкан жерге (тармактын негизинде) уруксат"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM-картага буйруктарды жөнөтүү"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"тармакка толук мүмкүнчүлүк алуу"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"профилди жана түзмөк ээлерин башкаруу"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX абалын өзгөртүү"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam өткөрүү абалын кабыл алуу"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"медиа чыгарылышын багыттоо"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"орнотуу сеанстарын окуу"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"топтомдорду орнотууга уруксат суроо"</string>
 </resources>
diff --git a/core/res/res/values-lo-rLA-watch/strings.xml b/core/res/res/values-lo-rLA-watch/strings.xml
index d7e97fb..db2f7e4 100644
--- a/core/res/res/values-lo-rLA-watch/strings.xml
+++ b/core/res/res/values-lo-rLA-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"ແອັບ <xliff:g id="NUMBER_0">%1$d</xliff:g> ໃນ <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"ເຊັນເຊີ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"ເຂົ້າ​ຫາ​ລາຍ​ຊື່​ຂອງ​ທ່ານ"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ເຂົ້າ​ຫາ​ທີ່​ຕັ້ງ​ຂອງ​ໂມງ​ນີ້"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"ເຂົ້າ​ຫາ​ປະ​ຕິ​ທິນ​ຂອງ​ທ່ານ"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"ສົ່ງ ແລະ​ ເບິ່ງ​ຂໍ້​ຄວາມ SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"ເຂົ້າເຖິງຮູບຖ່າຍ, ສື່ ແລະ ໄຟລ໌ຢູ່ເທິງໂມງຂອງທ່ານ"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ບັນທຶກສຽງ"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ຖ່າຍ​ຮູບ ແລະ ​ບັນ​ທຶກວິ​ດີ​ໂອ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ໂທ ແລະ​ ຈັດ​ການ​ການ​ໂທ​ລະ​ສັບ"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ເຂົ້າ​ຫາ​ຂໍ້​ມູນ​ເຊັນ​ເຊີ​ກ່ຽວ​ກັບ​ສັນ​ຍານ​ຊີບ​ຂອງ​ທ່ານ"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ເປັນ​ແຖບ​ສະ​ຖາ​ນະ"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ເຂົ້າ​ຫາເຊັນ​ເຊີ​​ກວດຮ່າງ​ກາຍ (ເຊັ່ນ: ​ຈໍຕິດ​ຕາມ​ອັດ​ຕາ​ການ​ເຕັ້ນ​ຂອງຫົວ​ໃຈ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ເຂົ້າ​ຫາທີ່ຕັ້ງທີ່ແນ່ນອນ (ອີງໃສ່ GPS ແລະ ເຄືອຂ່າຍ)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ເຂົ້າ​ຫາທີ່ຕັ້ງໂດຍປະມານ (ອີງໃສ່ເຄືອຂ່າຍ)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ສົ່ງ​ຄຳ​ສັ່ງ​ຫາ SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ມີ​ການເຂົ້າເຖິງເຄືອຂ່າຍເຕັມຮູບແບບ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ຈັດ​ການ​ເຈົ້າ​ຂອງ​ໂປ​ຣ​ໄຟ​ລ໌ ແລະ​ ອຸ​ປະ​ກອນ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"ປ່ຽນສະຖານະ WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ຮັບ​ສະ​ຖາ​ນະ​ການ​ໂອນ​ຂໍ້​ມູນ Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"ກຳນົດຊ່ອງທາງອອກຂອງສື່"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ອ່ານ​ເຊສ​ຊັນ​ການ​ຕິດ​ຕັ້ງ"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ຂໍ​ຕິດ​ຕັ້ງ​ແພັກ​ເກດ"</string>
 </resources>
diff --git a/core/res/res/values-lt-watch/strings.xml b/core/res/res/values-lt-watch/strings.xml
index bf32040..ce154e70 100644
--- a/core/res/res/values-lt-watch/strings.xml
+++ b/core/res/res/values-lt-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g> programa iš <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Jutikliai"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"pasiekti kontaktus"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"pasiekti šio laikrodžio vietą"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"pasiekti kalendorių"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"siųsti ir peržiūrėti SMS pranešimus"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"pasiekti laikrodžio nuotraukas, mediją ir failus"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"įrašyti garsą"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotografuoti ir filmuoti"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"skambinti ir tvarkyti telefonų skambučius"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"pasiekti jutiklių duomenis apie gyvybinius ženklus"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"būti būsenos juosta"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"pasiekti kūno jutiklius (pvz., pulso dažnio stebėjimo įrenginius)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"pasiekti tikslią vietą (nustatytą atsižvelgiant į GPS ir tinklą)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"pasiekti apytikslę vietą (nustatytą atsižvelgiant į tinklą)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"siųsti komandas į SIM kortelę"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"turėti visateisę tinklo prieigą"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"tvarkyti profilio ir įrenginio savininkus"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"keisti „WiMAX“ būseną"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"gauti „Android“ perdavimo funkcijos perkėlimo būseną"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"nukreipti medijos išvestį"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"skaityti diegimo sesijas"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"pateikti užklausą dėl diegimo paketų"</string>
 </resources>
diff --git a/core/res/res/values-lv-watch/strings.xml b/core/res/res/values-lv-watch/strings.xml
index 3a7fd95..c44677f 100644
--- a/core/res/res/values-lv-watch/strings.xml
+++ b/core/res/res/values-lv-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>. lietotne no <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensori"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"Piekļūt jūsu kontaktpersonu datiem"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"Piekļūt šī pulksteņa atrašanās vietas datiem"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"Piekļūt jūsu kalendāram"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"Sūtīt un skatīt īsziņas"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Piekļūt fotoattēliem, multivides saturam un failiem pulkstenī"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"Ierakstīt audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"Uzņemt attēlus un ierakstīt videoklipus"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"Veikt un pārvaldīt tālruņa zvanus"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"Piekļūt sensoru datiem par jūsu veselības rādījumiem"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"Būt par statusa joslu"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"Piekļūt ķermeņa sensoriem (piemēram, sirdsdarbības monitoriem)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"Noteikt precīzu atrašanās vietu (izmantojot GPS un tīklu)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"Noteikt aptuveno atrašanās vietu (izmantojot tīklu)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"Sūtīt komandas SIM kartei"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"Pilnīga piekļuve tīklam"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"Pārvaldīt profilus un ierīces īpašniekus"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"Mainīt WiMAX statusu"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Saņemt Android Beam pārsūtīšanas statusu"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"Maršrutēt multivides datu izeju"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"Lasīt instalēšanas sesijas"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"Pieprasīt pakotņu instalēšanu"</string>
 </resources>
diff --git a/core/res/res/values-mcc204-mnc12/config.xml b/core/res/res/values-mcc204-mnc12/config.xml
new file mode 100644
index 0000000..80432d7
--- /dev/null
+++ b/core/res/res/values-mcc204-mnc12/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>20408</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc450-mnc06/config.xml b/core/res/res/values-mcc450-mnc06/config.xml
index 63f9823..819c2a5 100644
--- a/core/res/res/values-mcc450-mnc06/config.xml
+++ b/core/res/res/values-mcc450-mnc06/config.xml
@@ -25,4 +25,7 @@
     -->
     <integer name="config_mobile_mtu">1428</integer>
 
+    <!-- Do not set the system language as value of EF LI/EF PL -->
+    <bool name="config_use_sim_language_file">false</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc450-mnc08/config.xml b/core/res/res/values-mcc450-mnc08/config.xml
index 950c62b..ca26ec1 100644
--- a/core/res/res/values-mcc450-mnc08/config.xml
+++ b/core/res/res/values-mcc450-mnc08/config.xml
@@ -25,4 +25,7 @@
     -->
     <integer name="config_mobile_mtu">1450</integer>
 
+    <!-- Do not set the system language as value of EF LI/EF PL -->
+    <bool name="config_use_sim_language_file">false</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc730-mnc01/config.xml b/core/res/res/values-mcc730-mnc01/config.xml
new file mode 100644
index 0000000..22f4027
--- /dev/null
+++ b/core/res/res/values-mcc730-mnc01/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>73010</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc730-mnc07/config.xml b/core/res/res/values-mcc730-mnc07/config.xml
new file mode 100644
index 0000000..836ddf9
--- /dev/null
+++ b/core/res/res/values-mcc730-mnc07/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>73002</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc730-mnc08/config.xml b/core/res/res/values-mcc730-mnc08/config.xml
new file mode 100644
index 0000000..836ddf9
--- /dev/null
+++ b/core/res/res/values-mcc730-mnc08/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>73002</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mcc730-mnc10/config.xml b/core/res/res/values-mcc730-mnc10/config.xml
new file mode 100644
index 0000000..58b7d78
--- /dev/null
+++ b/core/res/res/values-mcc730-mnc10/config.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You my obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT 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">
+    <!-- Don't use roaming icon for considered operators -->
+    <string-array translatable="false" name="config_operatorConsideredNonRoaming">
+        <item>73001</item>
+    </string-array>
+</resources>
diff --git a/core/res/res/values-mk-rMK-watch/strings.xml b/core/res/res/values-mk-rMK-watch/strings.xml
index 5e67a61..9d7c5bf 100644
--- a/core/res/res/values-mk-rMK-watch/strings.xml
+++ b/core/res/res/values-mk-rMK-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Апликац. <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Сензори"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"пристапи до контактите"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"пристапи до локацијата на часовникот"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"пристапи до календарот"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"испраќај и прикажувај СМС-пораки"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"пристапи до фотографиите, медиумите и датотеките на часовникот"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"снимај аудио"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"фотографирај и снимај видео"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"повикувај и управувај со телефонски повици"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"пристапи до податоците од сензорите за виталните знаци"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"биди статусната лента"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"пристапи до телесните сензори (како монитори за ритам на срце)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"пристапи до прецизната локација (ГПС и врз база на мрежа)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"пристапи до приближната локација (врз база на мрежа)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"испраќај наредби до СИМ-картичката"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"добиј целосен пристап до мрежата"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"управувај со сопствениците на профил и уред"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"промени ја состојбата на WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"добиј статус на пренос на Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"насочи излез за медиуми"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"читај сесии на инсталирање"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"барај пакети за инсталирање"</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN-watch/strings.xml b/core/res/res/values-ml-rIN-watch/strings.xml
index c10769e..02fe66c 100644
--- a/core/res/res/values-ml-rIN-watch/strings.xml
+++ b/core/res/res/values-ml-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g> അപ്ലിക്കേഷൻ."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"സെൻസറുകൾ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"നിങ്ങളുടെ കോൺടാക്റ്റുകൾ ആക്സസ് ചെയ്യുക"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ഈ വാച്ചിന്റെ ലൊക്കേഷൻ ആക്സസ് ചെയ്യുക"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"നിങ്ങളുടെ കലണ്ടർ ആക്സസ് ചെയ്യുക"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS സന്ദേശങ്ങൾ അയയ്‌ക്കുകയും കാണുകയും ചെയ്യുക"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"നിങ്ങളുടെ വാച്ചിൽ ഫോട്ടോകളും മീഡിയയും ഫയലുകളും ആക്സസ് ചെയ്യുക"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ഓഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ചിത്രങ്ങൾ എടുക്കുക, വീഡിയോ റെക്കോർഡ് ചെയ്യുക"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ഫോൺ വിളിക്കുകയും നിയന്ത്രിക്കുകയും ചെയ്യുക"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"നിങ്ങളുടെ ജീവാധാര ലക്ഷണങ്ങളെ കുറിച്ചുള്ള സെൻസർ വിവരങ്ങൾ ആക്സസ് ചെയ്യുക"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"സ്റ്റാറ്റസ് ബാർ ആയിരിക്കുക"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ശരീര സെൻസറുകൾ (ഹൃദയമിടിപ്പ് നിരക്ക് മോണിറ്ററുകൾ പോലെ) ആക്സസ് ചെയ്യുക"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"കൃത്യമായ ലൊക്കേഷൻ (GPS - നെറ്റ്‌വർക്ക് അധിഷ്ഠിതം) ആക്സസ് ചെയ്യുക"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ഏകദേശ ലൊക്കേഷൻ (നെറ്റ്‌വർക്ക് അധിഷ്ഠിതം) ആക്സസ് ചെയ്യുക"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM കമാൻഡുകൾ അയയ്ക്കുക"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"പൂർണ്ണ നെറ്റ്‌വർക്ക് ആക്സസ് ഉണ്ടായിരിക്കുക"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"പ്രൊഫൈൽ, ഉപകരണ ഉടമകളെ മാനേജുചെയ്യുക"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX നില മാറ്റുക"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android ബീം കൈമാറൽ നില സ്വീകരിക്കുക"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"മീഡിയ ഔട്ട്പുട്ട് റൂട്ടുചെയ്യുക"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ഇൻസ്‌റ്റാൾ സെഷനുകൾ റീഡുചെയ്യുക"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"പാക്കേജുകൾ ഇൻസ്റ്റാൾ ചെയ്യാൻ അഭ്യർത്ഥിക്കുക"</string>
 </resources>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index 43264a7..2bdc9c8 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -1149,7 +1149,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"ഇനങ്ങൾ ഇല്ലാതാക്കുക"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"ഇല്ലാതാക്കിയവ പഴയപടിയാക്കുക"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"ഇപ്പോൾ ഒന്നും ചെയ്യേണ്ടതില്ല"</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"ഒരു അക്കൗണ്ട് തിരഞ്ഞെടുക്കുക"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"അക്കൗണ്ട് തിരഞ്ഞെടുക്കൂ"</string>
     <string name="add_account_label" msgid="2935267344849993553">"ഒരു അക്കൗണ്ട് ചേർക്കുക"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"അക്കൗണ്ട് ചേർക്കുക"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"വർദ്ധിപ്പിക്കുക"</string>
diff --git a/core/res/res/values-mn-rMN-watch/strings.xml b/core/res/res/values-mn-rMN-watch/strings.xml
index 7b2e21b..6387aed 100644
--- a/core/res/res/values-mn-rMN-watch/strings.xml
+++ b/core/res/res/values-mn-rMN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-ны <xliff:g id="NUMBER_1">%2$d</xliff:g> апп."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Мэдрэгч"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"харилцагчийн хаягт хандах"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"энэ цагийн байршилд хандах"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"Хуанлид хандах"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS мессежийг илгээх, харах"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Цагныхаа зураг, медиа, файлд хандах"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"дуу хураах"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"зураг авах, бичлэг хийх"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"залгах, дуудлагыг зохион байгуулах"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"таны биеийн байдлын талаарх мэдрэгч бүхий өгөгдөлд хандах"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"статус мөр байхыг зөвшөөрөх"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"бие мэдрэгчид (зүрхний түвшин шалгагч г.м) хандах"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"тодорхой байршилд (GPS, сүлжээнд суурилсан) хандах"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ойролцоох байршилд (сүлжээнд суурилсан) хандах"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM карт руу комманд илгээх"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"сүлжээнд бүрэн нэвтрэх"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"Профайл, төхөөрөмж эзэмшигчийг зохион байгуулах"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX статусыг солих"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam дамжуулалтын статусыг хүлээн авах"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"Медиа хадгалах байршлыг тодорхойлох"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"Суулгах үеийг унших"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"Багц суулгахыг хүсэх"</string>
 </resources>
diff --git a/core/res/res/values-mr-rIN-watch/strings.xml b/core/res/res/values-mr-rIN-watch/strings.xml
index 11af412..0a60aad 100644
--- a/core/res/res/values-mr-rIN-watch/strings.xml
+++ b/core/res/res/values-mr-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> पैकी <xliff:g id="NUMBER_0">%1$d</xliff:g> अॅप"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"सेन्सर"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"आपल्या संपर्कांमध्ये प्रवेश करा"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"या घड्याळाच्या स्थानामध्ये प्रवेश करा"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"आपल्या कॅलेंडरमध्ये प्रवेश करा"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS संदेश पाठवा आणि पहा"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"आपल्‍या घड्याळावरील फोटो, मीडिया आणि फायलींमध्‍ये प्रवेश करा"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ऑडिओ रेकॉर्ड करा"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"चित्रे घ्या आणि व्हिडिओ रेकॉर्ड करा"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"फोन कॉल करा आणि व्यवस्थापित करा"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"आपल्‍या महत्त्वाच्या मापनांविषयी सेन्सर डेटामध्‍ये प्रवेश करा"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"स्टेटस बार होऊ द्या"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"शरीर सेन्सरमध्ये (हृदय गती मॉनिटरसारखे) प्रवेश करा"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"अचूक स्थानामध्ये (GPS आणि नेटवर्क-आधारित) प्रवेश करा"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"अंदाजे स्‍थानामध्ये (नेटवर्क-आधारित) प्रवेश करा"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"सिमला आदेश पाठवा"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"पूर्ण नेटवर्क प्रवेश आहे"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"प्रोफाईल आणि डिव्हाइस मालक व्यवस्थापित करा"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX स्थिती बदला"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android बीम स्थानांतरण स्थिती प्राप्त करा"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"मीडिया आउटपुट मार्गस्थ करा"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"स्‍थापना सत्र वाचा"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"पॅकेज स्थापित करण्यासाठी विनंती करा"</string>
 </resources>
diff --git a/core/res/res/values-ms-rMY-watch/strings.xml b/core/res/res/values-ms-rMY-watch/strings.xml
index d8245ed..c3f68b8 100644
--- a/core/res/res/values-ms-rMY-watch/strings.xml
+++ b/core/res/res/values-ms-rMY-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Apl <xliff:g id="NUMBER_0">%1$d</xliff:g> daripada <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Penderia"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"akses kenalan anda"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"akses lokasi jam tangan ini"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"akses kalendar anda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"hantar dan lihat mesej SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"akses foto, media dan fail pada jam tangan anda"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"rakam audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ambil gambar dan rakam video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"buat dan urus panggilan telefon"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"akses data penderia tentang tanda vital anda"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"jadi bar status"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"akses penderia badan (seperti pemantau kadar denyut jantung)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"akses lokasi tepat (GPS dan berdasarkan rangkaian)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"akses lokasi anggaran (berdasarkan rangkaian)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"hantar perintah ke SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"mempunyai akses rangkaian penuh"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"urus pemilik profil dan peranti"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"tukar keadaan WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"terima status pemindahan Pancaran Android"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"halakan output media"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"baca sesi pemasangan"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"minta pakej pemasangan"</string>
 </resources>
diff --git a/core/res/res/values-my-rMM-watch/strings.xml b/core/res/res/values-my-rMM-watch/strings.xml
index 34bd033..c4d738a 100644
--- a/core/res/res/values-my-rMM-watch/strings.xml
+++ b/core/res/res/values-my-rMM-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>၏  <xliff:g id="NUMBER_0">%1$d</xliff:g> ‌အသေးစားဆော့ဝဲ"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"အာရုံခံကိရိယာများ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"သင့် အဆက်အသွယ်များကို ယူသုံးရန်"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ဒီနာရီရဲ့ တည်နေရာကို ရယူရန်"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"သင့် ပြက္ခဒိန်ကို ယူသုံးရန်"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS စာတိုများကို ပို့ရန် နှင့် ကြည့်ရန်"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"သင့်နာရီထဲက ဓာတ်ပုံများ၊ မီဒီယာ၊ နှင့် ဖိုင်များကို ရယူသုံးရန်"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"အသံ ဖမ်းရန်"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ဓာတ်ပုံ ရိုက်ရန် နှင့် ဗွီဒီယို မှတ်တမ်းတင်ရန်"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ဖုန်းခေါ်ဆိုမှုများ ပြုလုပ်ရန် နှင့် စီမံရန်"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"သင်ရဲ့ အဓိက အသက်ရှင်မှုဆိုင်ရာ အာရုံခံကိရိယာ ဒေတာကို ရယူသုံးစွဲရန်"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"အခြေအနေပြ ဘားဖြစ်ပါစေ"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ခန္ဓာကိုယ် အာရုံကိရိယာများကို (နှလုံးခုန်နှုန်း မော်နီတာလို)ကို ရယူသုံးရန်"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"တိကျတဲ့ တည်နေရာ (GPS နှင့် ကွန်ရက် အခြေခံ)ကို ရယူသုံးရန်"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"အနီးစပ်ဆုံး တည်နေရာ (ကွန်ရက် အခြေခံ)ကို ရယူသုံးရန်"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM ထံသို့ ညွှန်ကြားချက်များကို ပို့တယ်"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ကွန်ရက်ကို အပြည့်အဝ ရယူသုံးနိုင်"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ပရိုဖိုင် နှင့် ကိရိယာ ပိုင်ရှင်များကို စီမံပါ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX အခြေအနေကို ပြောင်းရန်"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android ရဲ့ အလင်းတန်းထိုး လွှဲပြောင်းမှု အခြေအနေကို ရယူရန်"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"မီဒီယာ ထွက်ပေါက်ကို လမ်းဖေါ်ပြပေးပါ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"တပ်ဆင်ရေး လုပ်ကိုင်မှုကို ဖတ်ရန်"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"တပ်ဆင်ရေး အထုပ်များကို တောင်းဆိုပါ"</string>
 </resources>
diff --git a/core/res/res/values-nb-watch/strings.xml b/core/res/res/values-nb-watch/strings.xml
index aba8abb..249026c 100644
--- a/core/res/res/values-nb-watch/strings.xml
+++ b/core/res/res/values-nb-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorer"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"se kontaktene dine"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"få tilgang til posisjonen til denne klokken"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"åpne kalenderen din"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"sende og lese SMS-meldinger"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"få tilgang til bilder, media og filer på klokken din"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"spille inn lyd"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ta bilder og ta opp video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ringe og administrere anrop"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"få tilgang til sensordata om de vitale tegnene dine"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"vise appen i statusfeltet"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"få tilgang til kroppssensorer (for eksempel pulsmålere)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"få tilgang til nøyaktig posisjon (GPS- og nettverksbasert)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"få tilgang til omtrentlig posisjon (nettverksbasert)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"sende kommandoer til SIM-kortet"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"få full nettverkstilgang"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"administrere profiler og enhetseiere"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"endre WiMAX-statusen"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"motta overføringsstatus for Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"videresende medieutdata"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"lese installeringsøkter"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"be om installasjon av pakker"</string>
 </resources>
diff --git a/core/res/res/values-ne-rNP-watch/strings.xml b/core/res/res/values-ne-rNP-watch/strings.xml
index fe331bd..1b4ffc9 100644
--- a/core/res/res/values-ne-rNP-watch/strings.xml
+++ b/core/res/res/values-ne-rNP-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g> को <xliff:g id="NUMBER_0">%1$d</xliff:g> अनुप्रयोग।"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"सेन्सरहरू"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"आफ्नो सम्पर्कको पहुँच गर्नुहोस्"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"यो घडीको स्थान पहुँच गर्नुहोस्"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"आफ्नो पात्रोमा पहुँच गर्नुहोस्"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS सन्देशहरू पठाउनुहोस् र हेर्नुहोस्"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"आफ्नो समयमा तस्बिर, मिडिया, र फाइलहरू हेर्नुहोस्"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"अडियो रेकर्ड गर्नुहोस्"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"तस्बिरहरू खिच्नुहोस् र भिडियो रेकर्ड गर्नुहोस्"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"फोन कलहरू गर्नुहोस् र व्यवस्थापन गर्नुहोस्"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"आफ्नो महत्त्वपूर्ण संकेत बारेको सेन्सर डेटा पहुँच गर्नुहोस्"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"वस्तुस्थिति पट्टी हुन"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"शरीरका सेन्सरहरू पहुँच गर्नुहोस् (जस्तै हृदय धड्कन निगरानी)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"सटीक स्थान पहुँच गर्नुहोस् (GPS र नेटवर्क आधारित)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"अनुमानित स्थान पहुँच गर्नुहोस् (नेटवर्क आधारित)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"यस SIM मा आदेशहरू पठाउनहोस्"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"पूर्ण नेटवर्क पहुँच प्राप्त"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"प्रोफाइल र यन्त्र मालिकहरूको व्यवस्थापन गर्नुहोस्"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX अवस्था परिवर्तन गर्नुहोस्"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam स्थानान्तरण अवस्था प्राप्त गर्नुहोस्"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"मिडिया परिणाम दिशानिर्देश गर्नुहोस्"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"स्थापना सत्रहरू पढ्नुहोस्"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"स्थापना प्याकेजहरू अनुरोध गर्नुहोस्"</string>
 </resources>
diff --git a/core/res/res/values-nl-watch/strings.xml b/core/res/res/values-nl-watch/strings.xml
index bed8a11..590d146 100644
--- a/core/res/res/values-nl-watch/strings.xml
+++ b/core/res/res/values-nl-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> van <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensoren"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"toegang tot uw contacten"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"toegang tot de locatie van dit horloge"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"toegang tot uw agenda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"sms\'jes verzenden en bekijken"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"toegang tot foto\'s, media en bestanden op uw horloge"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"audio opnemen"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"foto\'s maken en video opnemen"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"bellen en telefoontjes beheren"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"toegang tot sensorgegevens over uw vitale functies"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"de statusbalk zijn"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"toegang tot lichaamssensoren (zoals hartslagmeters)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"toegang tot precieze locatie (GPS- en netwerkgebaseerd)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"toegang tot geschatte locatie (netwerkgebaseerd)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"opdrachten verzenden naar de simkaart"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"volledige netwerktoegang"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profiel- en apparaateigenaren beheren"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX-status wijzigen"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam-overdrachtsstatus ontvangen"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"media-uitvoer aansturen"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"installatiesessies lezen"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"installatiepakketten aanvragen"</string>
 </resources>
diff --git a/core/res/res/values-pa-rIN-watch/strings.xml b/core/res/res/values-pa-rIN-watch/strings.xml
index addaa6b..e5cb9e1 100644
--- a/core/res/res/values-pa-rIN-watch/strings.xml
+++ b/core/res/res/values-pa-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"ਐਪ <xliff:g id="NUMBER_1">%2$d</xliff:g> ਦਾ <xliff:g id="NUMBER_0">%1$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"ਸੰੰਵੇਦਕ"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"ਤੁਹਾਡੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਪ"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ਇਸ ਘੜੀ ਦੇ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਤੱਕ ਪਹੁੰਚ"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਦਿਖਾਓ"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"ਤੁਹਾਡੀ ਘੜੀ ਤੇ ਮੌਜੂਦ ਫੋਟੋਆਂ, ਮੀਡੀਆ ਅਤੇ ਫਾਈਲਾਂ ਤੱਕ ਪਹੁੰਚ"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ਔਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ਤਸਵੀਰਾਂ ਖਿੱਚੋ ਅਤੇ ਵੀਡੀਓ ਰਿਕਾਰਡ ਕਰੋ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ਫ਼ੋਨ ਕਾਲਾਂ ਕਰੋ ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਪ੍ਰਬੰਧਿਤ ਕਰੋ"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ਆਪਣੇ ਮਹੱਤਵਪੂਰਣ ਲੱਛਣਾਂ ਬਾਰੇ ਸੰਵੇਦਕ ਡਾਟਾ ਤੱਕ ਪਹੁੰਚ"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ਸਥਿਤੀ ਬਾਰ ਹੋਵੋ"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"ਸਰੀਰ ਸੰਵੇਦਕਾਂ ਤੱਕ ਪਹੁੰਚ (ਜਿਵੇਂ ਦਿਲ ਦੀ ਧੜਕਣ ਦੇ ਨਿਰੀਖਕ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ਨਿਯਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਤੱਕ ਪਹੁੰਚ (GPS ਅਤੇ ਨੈਟਵਰਕ-ਆਧਾਰਿਤ)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ਅਨੁਮਾਨਿਤ ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਤੱਕ ਪਹੁੰਚ (ਨੈਟਵਰਕ-ਆਧਾਰਿਤ)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM ਨੂੰ ਕਮਾਂਡਾਂ ਭੇਜੋ"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ਪੂਰੀ ਨੈਟਵਰਕ ਪਹੁੰਚ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ਪ੍ਰੋਫ਼ਾਈਲ ਅਤੇ ਡਿਵਾਈਸ ਦੇ ਮਾਲਕਾਂ ਨੂੰ ਪ੍ਰਬੰਧਿਤ ਕਰੋ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX ਸਥਿਤੀ ਬਦਲੋ"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam ਟ੍ਰਾਂਸਫਰ ਸਥਿਤੀ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"ਰੂਟ ਮੀਡੀਆ ਆਊਟਪੁਟ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ਇੰਸਟੌਲ ਸੈਸ਼ਨ ਪੜ੍ਹੋ"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ਪੈਕੇਜ ਇੰਸਟੌਲ ਕਰਨ ਦੀ ਬੇਨਤੀ ਕਰੋ"</string>
 </resources>
diff --git a/core/res/res/values-pl-watch/strings.xml b/core/res/res/values-pl-watch/strings.xml
index f266d0a..ff9f7ea 100644
--- a/core/res/res/values-pl-watch/strings.xml
+++ b/core/res/res/values-pl-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikacja <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Czujniki"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"dostęp do kontaktów"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"dostęp do lokalizacji tego zegarka"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"dostęp do kalendarza"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"wysyłanie i wyświetlanie SMS-ów"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"dostęp do zdjęć, multimediów i plików na Twoim zegarku"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"nagrywanie dźwięku"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"robienie zdjęć i nagrywanie filmów"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"nawiązywanie połączeń telefonicznych i zarządzanie nimi"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"dostęp do danych czujnika podstawowych funkcji życiowych"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"działanie jako pasek stanu"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"dostęp do czujników ciała (np. monitorujących tętno)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"dostęp do dokładnej lokalizacji (na podstawie GPS-u i sieci)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"dostęp do przybliżonej lokalizacji (na podstawie sieci)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"wysyłanie poleceń do karty SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"pełny dostęp do sieci"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"zarządzanie właścicielami profilu i urządzenia"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"zmiana stanu WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"uzyskiwanie informacji o stanie transmisji Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"kierowanie wyjścia multimediów"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"odczytywanie sesji instalacji"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"żądanie instalacji pakietów"</string>
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 1086601..82d1c02 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -421,10 +421,10 @@
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"używanie czytnika linii papilarnych"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Zezwala aplikacji na używanie czytnika linii papilarnych na potrzeby autoryzacji"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Odcisk palca został odczytany tylko częściowo. Spróbuj ponownie."</string>
-    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nie udało się przetworzyć linii papilarnych. Spróbuj ponownie."</string>
+    <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Nie udało się przetworzyć odcisku palca. Spróbuj ponownie."</string>
     <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Czytnik linii papilarnych jest zabrudzony. Wyczyść go i spróbuj ponownie."</string>
-    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Palec został uniesiony zbyt szybko. Spróbuj ponownie."</string>
-    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Palec został przesunięty zbyt wolno. Spróbuj ponownie."</string>
+    <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Palec został podniesiony zbyt wcześnie. Spróbuj jeszcze raz."</string>
+    <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Palec został obrócony zbyt wolno. Spróbuj ponownie."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
     <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Czytnik linii papilarnych nie jest dostępny."</string>
@@ -433,7 +433,7 @@
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Odczyt odcisku palca został anulowany."</string>
     <string name="fingerprint_error_lockout" msgid="5536934748136933450">"Zbyt wiele prób. Spróbuj ponownie później."</string>
     <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"Spróbuj ponownie."</string>
-    <string name="fingerprint_name_template" msgid="5870957565512716938">"Palec <xliff:g id="FINGERID">%d</xliff:g>"</string>
+    <string name="fingerprint_name_template" msgid="5870957565512716938">"Odcisk palca <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Ikona odcisku palca"</string>
diff --git a/core/res/res/values-pt-rBR-watch/strings.xml b/core/res/res/values-pt-rBR-watch/strings.xml
index 0eb0da3..a5e4a11 100644
--- a/core/res/res/values-pt-rBR-watch/strings.xml
+++ b/core/res/res/values-pt-rBR-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acessar seus contatos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"acessar a localização deste relógio"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acessar sua agenda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar e ver mensagens SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"acessar fotos, mídia e arquivos do seu relógio"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"grave áudio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tire fotos e grave vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fazer e gerenciar chamadas telefônicas"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acessar dados do sensor sobre seus sinais vitais"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ser a barra de status"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"acessar os sensores corporais (como monitores de frequência cardíaca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"acessar a localização precisa (GPS e com base na rede)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"acessar a localização aproximada (com base na rede)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos para o SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ter acesso total à rede"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gerenciar proprietários de perfis e de dispositivos"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"alterar estado do WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receber status de transferência do Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"rotear saída de mídia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ler sessões de instalação"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar pacotes de instalação"</string>
 </resources>
diff --git a/core/res/res/values-pt-rPT-watch/strings.xml b/core/res/res/values-pt-rPT-watch/strings.xml
index 1654fc3..0dd354a 100644
--- a/core/res/res/values-pt-rPT-watch/strings.xml
+++ b/core/res/res/values-pt-rPT-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplicação <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"aceder aos contactos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"aceder à localização deste relógio"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"aceder ao calendário"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar e ver mensagens SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"aceder a fotos, a multimédia e a ficheiros no relógio"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"gravar áudio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tirar fotos e gravar vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fazer e gerir chamadas"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"aceder a dados do sensor acerca dos seus sinais vitais"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ser apresentada na barra de estado"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"aceder aos sensores corporais (como monitores do ritmo cardíaco)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"aceder à localização exata (baseada no GPS e na rede)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"aceder à localização aproximada (baseada na rede)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos para o SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ter acesso total à rede"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gerir proprietários de perfis e de dispositivos"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"alterar estado do WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receber estado de transferências do Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"encaminhar saída de som multimédia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ler sessões de instalação"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar a instalação de pacotes"</string>
 </resources>
diff --git a/core/res/res/values-pt-watch/strings.xml b/core/res/res/values-pt-watch/strings.xml
index 0eb0da3..a5e4a11 100644
--- a/core/res/res/values-pt-watch/strings.xml
+++ b/core/res/res/values-pt-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensores"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acessar seus contatos"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"acessar a localização deste relógio"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acessar sua agenda"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"enviar e ver mensagens SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"acessar fotos, mídia e arquivos do seu relógio"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"grave áudio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"tire fotos e grave vídeos"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fazer e gerenciar chamadas telefônicas"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acessar dados do sensor sobre seus sinais vitais"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"ser a barra de status"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"acessar os sensores corporais (como monitores de frequência cardíaca)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"acessar a localização precisa (GPS e com base na rede)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"acessar a localização aproximada (com base na rede)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"enviar comandos para o SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ter acesso total à rede"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"gerenciar proprietários de perfis e de dispositivos"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"alterar estado do WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"receber status de transferência do Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"rotear saída de mídia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ler sessões de instalação"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"solicitar pacotes de instalação"</string>
 </resources>
diff --git a/core/res/res/values-ro-watch/strings.xml b/core/res/res/values-ro-watch/strings.xml
index dc3c906..e412cad 100644
--- a/core/res/res/values-ro-watch/strings.xml
+++ b/core/res/res/values-ro-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplic. <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"să acceseze persoanele de contact"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"să acceseze locația acestui ceas"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"să acceseze calendarul"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"să trimită și să vadă mesajele SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"să acceseze fotografiile, conținutul media și fișierele de pe ceas"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"să înregistreze conținut audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"să fotografieze și să înregistreze videoclipuri"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"să inițieze să și gestioneze apeluri telefonice"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"să acceseze datele de la senzori despre semnele vitale"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"să fie bara de stare"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"să acceseze locația aproximativă (bazată pe rețea)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"să trimită comenzi către SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"să aibă acces deplin la rețea"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"să gestioneze profilul și proprietarii dispozitivului"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"să schimbe starea WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"să primească starea transferului prin Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"să direcționeze rezultatele media"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"să citească sesiunile de instalare"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"să solicite pachete de instalare"</string>
 </resources>
diff --git a/core/res/res/values-ru-watch/strings.xml b/core/res/res/values-ru-watch/strings.xml
index cd536c5..5dd5630 100644
--- a/core/res/res/values-ru-watch/strings.xml
+++ b/core/res/res/values-ru-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Приложение <xliff:g id="NUMBER_0">%1$d</xliff:g> из <xliff:g id="NUMBER_1">%2$d</xliff:g>"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Датчики"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"доступ к контактам"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"доступ к местоположению часов"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"доступ к календарю"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"отправка и просмотр SMS-сообщений"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"доступ к фото, медиа и файлам на часах"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"запись аудио"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"фото- и видеосъемка"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"осуществление телефонных звонков и управление ими"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"доступ к данным датчиков о состоянии организма"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"замена строки состояния"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"доступ к датчикам (например, пульсометру)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"доступ к точному местоположению (на основе GPS и данных сети)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"доступ к примерному местоположению (на основе данных сети)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"отправка команд SIM-карте"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"неограниченный доступ к Интернету"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"управление профилями и владельцами"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"изменение статуса WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"получение статуса передачи Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"перенаправление мультимедийных данных"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"чтение данных о сеансах установки"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"разрешение на установку пакетов"</string>
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 821342a..f1deb22 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1038,7 +1038,7 @@
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"Передача фото через USB"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI через USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB-устройство подключено"</string>
-    <string name="usb_notification_message" msgid="7347368030849048437">"Ещё варианты"</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Нажмите, чтобы настроить."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
     <string name="adb_active_notification_message" msgid="1016654627626476142">"Нажмите, чтобы отключить отладку по USB."</string>
     <string name="select_input_method" msgid="8547250819326693584">"Выбор раскладки"</string>
diff --git a/core/res/res/values-si-rLK-watch/strings.xml b/core/res/res/values-si-rLK-watch/strings.xml
index 4adfbb5..aad82a0 100644
--- a/core/res/res/values-si-rLK-watch/strings.xml
+++ b/core/res/res/values-si-rLK-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g> හි <xliff:g id="NUMBER_1">%2$d</xliff:g> යෙදුම."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"සංවේදක"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"ඔබේ සම්බන්ධතාවලට පිවිසීම"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"මෙම ඔරලෝසුවෙහි ස්ථානයට පිවිසීම"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"ඔබේ දින දර්ශනයට පිවිසීම"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS පණිවිඩ යැවීම සහ බැලීම"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"ඔබේ ඔරලෝසුවේ ඇති ඡායාරූප, මාධ්‍ය සහ ගොනුවලට පිවිසීම"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ශ්‍රව්‍ය පටිගත කිරීම"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"පින්තූර ගැනීම සහ වීඩියෝ පටිගත කිරීම"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"දුරකථන ඇමතුම් සිදු කිරීම සහ කළමනාකරණය කිරීම"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"ඔබේ ජෛව ලක්ෂණ පිළිබඳ සංවේදක දත්ත වෙත පිවිසීම"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"තත්ත්ව තීරුව බවට පත්වීම"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"දේහ සංවේදකවලට (හෘද ස්පන්දන වේග මොනිටර වැනි) පිවිසීම"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"නිවැරදි ස්ථානයට (GPS සහ ජාලය පදනම් කරගත්) පිවිසීම"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"ආසන්නතම ස්ථානයට (ජාලය-පාදක වූ) පිවිසීම"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM වෙත විධාන යැවීම"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"සම්පූර්ණ ජාල ප්‍රවේශය තබා ගැනීම"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"පැතිකඩ සහ උපාංග හිමිකරුවන් කළමනාකරණය කිරීම"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX තත්ත්වය වෙනස් කිරීම"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android කදම්බ හුවමාරු තත්ත්වය ලබා ගැනීම"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"මාධ්‍ය ප්‍රතිදානය මාර්ගගත කිරීම"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ස්ථාපන සැසි කියවීම"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ස්ථාපන පැකේජ ඉල්ලීම"</string>
 </resources>
diff --git a/core/res/res/values-sk-watch/strings.xml b/core/res/res/values-sk-watch/strings.xml
index 24bed89..765b390 100644
--- a/core/res/res/values-sk-watch/strings.xml
+++ b/core/res/res/values-sk-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikácia <xliff:g id="NUMBER_0">%1$d</xliff:g> z <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzory"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"prístup ku kontaktom"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"prístup k polohe týchto hodiniek"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"prístup ku kalendáru"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"posielanie a zobrazovanie správ SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"prístup k fotkám, médiám a súborom v hodinkách"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"zaznamenávanie zvuku"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotenie a zaznamenávanie videí"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefonovanie a správa hovorov"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"prístup k údajom senzorov o životných funkciách"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"vydávanie sa za stavový riadok"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"prístup k telesným senzorom (ako sú snímače tepu)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"prístup k presnej polohe (pomocou GPS a siete)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"prístup k približnej polohe (pomocou siete)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"posielanie príkazov do SIM karty"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"úplný prístup k sieti"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"správa vlastníkov profilov a zariadení"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"zmena stavu pripojenia WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"príjem stavu prenosov Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"smerovanie výstupu médií"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"čítanie inštalačných relácií"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"odosielanie žiadostí o inštaláciu balíčkov"</string>
 </resources>
diff --git a/core/res/res/values-sl-watch/strings.xml b/core/res/res/values-sl-watch/strings.xml
index 5bc0ea5..f138326 100644
--- a/core/res/res/values-sl-watch/strings.xml
+++ b/core/res/res/values-sl-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_0">%1$d</xliff:g>. aplikac. od <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Tipala"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"dostop do stikov"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"dostop do lokacije te ure"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"dostop do koledarja"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"pošiljanje in ogled sporočil SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"dostop do fotografij, predstavnosti in datotek v uri"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"snemanje zvoka"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotografiranje in snemanje videoposnetkov"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"opravljanje in upravljanje telefonskih klicev"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"dostop do podatkov tipala o vaših vitalnih znakih"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"postane vrstica stanja"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"dostop do tipal telesnih funkcij (npr. merilnikov srčnega utripa)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"dostop do natančne lokacije (na podlagi podatkov GPS in omrežja)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"dostop do približne lokacije (na podlagi podatkov omrežja)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"pošiljanje ukazov na kartico SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"poln dostop do omrežja"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"upravljanje lastnikov profilov in lastnika naprave"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"sprememba stanja omrežja WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"prejemanje stanja prenosov s funkcijo Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"preusmeritev predstavnosti"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"branje sej namestitev"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"zahtevanje paketov za namestitev"</string>
 </resources>
diff --git a/core/res/res/values-sq-rAL-watch/strings.xml b/core/res/res/values-sq-rAL-watch/strings.xml
index 1b0bdaf..7e36a32 100644
--- a/core/res/res/values-sq-rAL-watch/strings.xml
+++ b/core/res/res/values-sq-rAL-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplikacioni <xliff:g id="NUMBER_0">%1$d</xliff:g> nga <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorët"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"qasu te kontaktet e tua"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"qasu te vendndodhja e kësaj ore"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"qasu te kalendari yt"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"dërgo dhe shiko mesazhet SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"qasu te fotografitë, përmbajtjet audio-vizuale dhe skedarët në orën tënde të dorës"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"regjistro audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"bëj fotografi dhe regjistro video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"kryej dhe menaxho telefonata"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"qasu tek të dhënat e sensorëve rreth shenjave të tua jetësore"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"të bëhet shiriti i statusit"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"qasu te sensorët e trupit (si monitorimet e rrahjeve të zemrës)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"qasu te vendndodhja e përpiktë (në bazë të GPS-së dhe rrjetit)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"qasu te vendndodhja e përafërt (bazuar në rrjet)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"dërgo komanda te karta SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"qasu plotësisht në rrjet"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"menaxho zotëruesit e profilit dhe të pajisjes"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"ndrysho gjendjen WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"merr statusin e transferimit përmes \"Dërgimit me rreze të Android\""</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"kalo daljet e përmbajtjes audio-vizuale"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"lexo sesionet e instalimit"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"kërko paketat e instalimit"</string>
 </resources>
diff --git a/core/res/res/values-sr-watch/strings.xml b/core/res/res/values-sr-watch/strings.xml
index ae70ab1..afeae38 100644
--- a/core/res/res/values-sr-watch/strings.xml
+++ b/core/res/res/values-sr-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Апликација <xliff:g id="NUMBER_0">%1$d</xliff:g> од <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Сензори"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"приступ контактима"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"приступ локацији овог сата"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"приступ календару"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"слање и преглед SMS порука"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"приступ сликама, медијским и другим датотекама на сату"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"снимање аудио снимака"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"снимање слика и видео снимака"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"упућивање телефонских позива и управљање њима"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"приступ подацима сензора о виталним функцијама"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"функционисање као статусне траке"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"приступ сензорима на телу (попут монитора за праћење пулса)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"приступ прецизној локацији (утврђена преко мреже и GPS-а)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"приступ приближној локацији (утврђена преко мреже)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"слање команди на SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"има пун мрежни приступ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"управљање власницима профила и уређаја"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"мењање WiMAX статуса"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"пријем статуса пребацивања помоћу Android пребацивања"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"усмеравање излаза медија"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"читање сесија инсталирања"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"захтевање пакета за инсталирање"</string>
 </resources>
diff --git a/core/res/res/values-sv-watch/strings.xml b/core/res/res/values-sv-watch/strings.xml
index aba8abb..439b464 100644
--- a/core/res/res/values-sv-watch/strings.xml
+++ b/core/res/res/values-sv-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> av <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorer"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"få tillgång till dina kontakter"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"få tillgång till klockans plats"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"få tillgång till din kalender"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"skicka och visa sms"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"få åtkomst till foton, media och filer på klockan"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"spela in ljud"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ta bilder och spela in video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ringa och hantera telefonsamtal"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"få åtkomst till sensordata om dina vitalparametrar"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"visas i statusfältet"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"få åtkomst till kroppssensorer (till exempel pulsmätare)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"få åtkomst till din exakta position (GPS- och nätverksbaserad)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"få åtkomst till din ungefärliga position (nätverksbaserad)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"skicka kommandon till SIM-kortet"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"få fullständig nätverksåtkomst"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"hantera profil- och enhetsägare"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"ändra WiMAX-status"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"ta emot status för Android Beam-överföring"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"dirigera medieuppspelning"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"läsa installationssessioner"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"begära installationspaket"</string>
 </resources>
diff --git a/core/res/res/values-sw-watch/strings.xml b/core/res/res/values-sw-watch/strings.xml
index 929022f..3cad827 100644
--- a/core/res/res/values-sw-watch/strings.xml
+++ b/core/res/res/values-sw-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Programu ya <xliff:g id="NUMBER_0">%1$d</xliff:g> kati ya <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Vihisi"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"fikia anwani zako"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"tambua mahali saa hii ilipo"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"fikia kalenda yako"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"tuma na uangalie ujumbe wa SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"fikia picha, maudhui na faili kwenye saa yako"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"rekodi sauti"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"piga picha na urekodi video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"piga na udhibiti simu"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"fikia data ya kihisi kuhusu alama zako muhimu"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"kuwa sehemu ya arifa"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"fikia vihisi vya mwili (kama vifuatiliaji vya mapigo ya moyo)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"fikia mahali halisi (inategemea mtandao na GPS)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"fikia mahali karibu na hapo (inategemea mtandao)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"tuma amri kwenye SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"pata ufikiaji kamili wa mtandao"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"simamia wamiliki wa wasifu na vifaa"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"badilisha hali ya WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"pokea hali ya uhamisho wa Boriti ya Android"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"tuma njia ya kutoa maudhui"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"soma vipindi vya kusakinisha"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"omba ruhusa ya kusakinisha vifurushi"</string>
 </resources>
diff --git a/core/res/res/values-ta-rIN-watch/strings.xml b/core/res/res/values-ta-rIN-watch/strings.xml
index 23accbc..629ca27 100644
--- a/core/res/res/values-ta-rIN-watch/strings.xml
+++ b/core/res/res/values-ta-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"பயன்பாடு: <xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"உணர்விகள்"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"தொடர்புகளை அணுகும்"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"இந்த வாட்சின் இருப்பிடத்தை அணுகும்"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"கேலெண்டரை அணுகும்"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS செய்திகளை அனுப்பும் மற்றும் பார்க்கும்"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"உங்கள் வாட்சில் உள்ள படங்கள், மீடியா மற்றும் கோப்புகளை அணுகும்"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ஆடியோவைப் பதிவுசெய்யும்"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"படங்களை எடுக்கும், வீடியோவைப் பதிவுசெய்யும்"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"மொபைல் அழைப்புகளைச் செய்யும், நிர்வகிக்கும்"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"உங்கள் உடலியக்கக் குறிகள் பற்றிய உணர்வித் தரவை அணுகும்"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"நிலைப் பட்டியில் இருக்கும்"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"உடல் உணர்விகளை (இதயத் துடிப்பு மானிட்டர்கள் போன்றவை) அணுகும்"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"துல்லியமான இருப்பிடத்தை அணுகும் (GPS மற்றும் நெட்வொர்க் அடிப்படையில்)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"தோராயமான இருப்பிடத்தை அணுகும் (நெட்வொர்க் அடிப்படையில்)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"கட்டளைகளை சிம்மிற்கு அனுப்பும்"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"முழுமையான நெட்வொர்க் அணுகலைக் கொண்டிருக்கும்"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"சுயவிவரத்தையும் சாதன உரிமையாளர்களையும் நிர்வகிக்கும்"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX நிலையை மாற்றும்"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android பீம் பரிமாற்ற நிலையைப் பெறும்"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"மீடியா அவுட்புட்டை ரூட் செய்யும்"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"நிறுவல் அமர்வுகளைப் படிக்கும்"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"நிறுவல் தொகுப்புகளைக் கோரும்"</string>
 </resources>
diff --git a/core/res/res/values-te-rIN-watch/strings.xml b/core/res/res/values-te-rIN-watch/strings.xml
index 0843471..f642807 100644
--- a/core/res/res/values-te-rIN-watch/strings.xml
+++ b/core/res/res/values-te-rIN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>లో <xliff:g id="NUMBER_0">%1$d</xliff:g>వ అనువర్తనం."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"సెన్సార్‌లు"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"మీ పరిచయాలను ప్రాప్యత చేస్తుంది"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"ఈ గడియారం స్థానాన్ని ప్రాప్యత చేస్తుంది"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"మీ క్యాలెండర్‌ను ప్రాప్యత చేస్తుంది"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS సందేశాలను పంపుతుంది మరియు చూస్తుంది"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"మీ గడియారంలోని ఫోటోలు, మీడియా మరియు ఫైల్‌లను ప్రాప్యత చేస్తుంది"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ఆడియోను రికార్డ్ చేస్తుంది"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"చిత్రాలను తీస్తుంది మరియు వీడియోను రికార్డ్ చేస్తుంది"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"ఫోన్ కాల్‌లు చేస్తుంది మరియు నిర్వహిస్తుంది"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"మీ అత్యంత కీలకమైన గుర్తుల గురించి సెన్సార్ డేటాని ప్రాప్యత చేస్తుంది"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"స్థితి పట్టీగా ఉంటుంది"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"శరీర సెన్సార్‌లను (హృదయ స్పందన రేటు మానిటర్‌ల వంటివి) ప్రాప్యత చేస్తుంది"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"ఖచ్చితమైన స్థానాన్ని (GPS మరియు నెట్‌వర్క్-ఆధారితం) ప్రాప్యత చేస్తుంది"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"సమీప స్థానాన్ని (నెట్‌వర్క్-ఆధారితం) ప్రాప్యత చేస్తుంది"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIMకి ఆదేశాలు పంపుతుంది"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"పూర్తి నెట్‌వర్క్ ప్రాప్యతను కలిగి ఉంటుంది"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"ప్రొఫైల్ మరియు పరికరం యజమానులను నిర్వహిస్తుంది"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX స్థితిని మారుస్తుంది"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam బదిలీ స్థితిని స్వీకరిస్తుంది"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"మీడియా అవుట్‌పుట్ మార్గం నిర్దేశిస్తుంది"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"ఇన్‌స్టాల్ సెషన్‌లను చదువుతుంది"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ఇన్‌స్టాల్ ప్యాకేజీలను అభ్యర్థిస్తుంది"</string>
 </resources>
diff --git a/core/res/res/values-th-watch/strings.xml b/core/res/res/values-th-watch/strings.xml
index 9cc21b0..98f938d 100644
--- a/core/res/res/values-th-watch/strings.xml
+++ b/core/res/res/values-th-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"แอป <xliff:g id="NUMBER_0">%1$d</xliff:g> จาก <xliff:g id="NUMBER_1">%2$d</xliff:g> แอป"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"เซ็นเซอร์"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"เข้าถึงรายชื่อติดต่อ"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"เข้าถึงตำแหน่งของนาฬิกานี้"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"เข้าถึงปฏิทิน"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"ส่งและดูข้อความ SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"เข้าถึงรูปภาพ สื่อ และไฟล์ในนาฬิกา"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"บันทึกเสียง"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"ถ่ายภาพและบันทึกวิดีโอ"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"โทรและจัดการการโทร"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"เข้าถึงข้อมูลเซ็นเซอร์เกี่ยวกับสัญญาณชีพของคุณ"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"เป็นแถบสถานะ"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"เข้าถึงเซ็นเซอร์สำหรับร่างกาย (เช่น เครื่องติดตามดูอัตราการเต้นของหัวใจ)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"เข้าถึงตำแหน่งที่แม่นยำ (อิงจาก GPS และเครือข่าย)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"เข้าถึงตำแหน่งโดยประมาณ (อิงจากเครือข่าย)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"ส่งคำสั่งไปยังซิม"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"มีสิทธิ์เข้าถึงเครือข่ายเต็มรูปแบบ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"จัดการเจ้าของโปรไฟล์และอุปกรณ์"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"เปลี่ยนสถานะของ WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"รับสถานะการโอน Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"กำหนดเส้นทางเอาต์พุตของสื่อ"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"อ่านเซสชันการติดตั้ง"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"ขอติดตั้งแพ็กเกจ"</string>
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 9804f99..b2df636 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1026,7 +1026,7 @@
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"เชื่อมต่อกับอุปกรณ์เสริม USB แล้ว"</string>
     <string name="usb_notification_message" msgid="7347368030849048437">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่องของ USB"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"แตะเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
     <string name="select_input_method" msgid="8547250819326693584">"เปลี่ยนแป้นพิมพ์"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"เลือกแป้นพิมพ์"</string>
     <string name="show_ime" msgid="9157568568695230830">"แสดงวิธีการป้อนข้อมูล"</string>
diff --git a/core/res/res/values-tl-watch/strings.xml b/core/res/res/values-tl-watch/strings.xml
index 3fba2dc..c38891e 100644
--- a/core/res/res/values-tl-watch/strings.xml
+++ b/core/res/res/values-tl-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> ng <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Mga Sensor"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"i-access ang iyong mga contact"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"i-access ang lokasyon ng relong ito"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"i-access ang iyong kalendaryo"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"magpadala at tumingin ng mga mensaheng SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"i-access ang mga larawan, media at mga file sa iyong relo"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"mag-record ng audio"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"kumuha ng mga larawan at mag-record ng video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"tumawag sa telepono at mamahala ng mga tawag sa telepono"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"i-access ang data ng sensor tungkol sa iyong mahahalagang senyales"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"maging status bar"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"i-access ang mga sensor sa katawan (tulad ng mga monitor ng bilis ng tibok ng puso)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"i-access ang tumpak na lokasyon (batay sa GPS at network)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"i-access ang tinatantyang lokasyon (batay sa network)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"magpadala ng mga command sa SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"magkaroon ng ganap na access sa network"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"pamahalaan ang mga may-ari ng profile at device"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"baguhin ang status ng WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"tanggapin ang status ng paglilipat ng Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"iruta ang output ng media"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"basahin ang mga session ng pag-install"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"humiling ng mga package sa pag-install"</string>
 </resources>
diff --git a/core/res/res/values-tr-watch/strings.xml b/core/res/res/values-tr-watch/strings.xml
index b34ad74..4dbf664 100644
--- a/core/res/res/values-tr-watch/strings.xml
+++ b/core/res/res/values-tr-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Uygulama <xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensörler"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kişilerinize erişme"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"bu saatin konum bilgilerine erişme"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"takviminize erişme"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS iletileri gönderme ve görüntüleme"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"saatinizdeki fotoğraflara, medyaya ve dosyalara erişme"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ses kaydetme"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotoğraf çekme ve video kaydetme"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon aramaları yapma ve çağrıları yönetme"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"hayati belirtilerinizle ilgili sensör verilerine erişme"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"durum çubuğunda olma"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"vücut sensörlerine erişme (nabız takip cihazları gibi)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"konumunuza hassas olarak erişme (GPS ve ağ tabanlı)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"konumunuza yaklaşık olarak erişme (ağ tabanlı)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM karta komut gönderme"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"tam ağ erişimine sahip olma"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profili ve cihaz sahiplerini yönetme"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX durumunu değiştirme"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam aktarım durumunu alma"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"medya çıkışını yönlendirme"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"yükleme oturumlarını okuma"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"paketleri yükleme isteğinde bulunma"</string>
 </resources>
diff --git a/core/res/res/values-uk-watch/strings.xml b/core/res/res/values-uk-watch/strings.xml
index 4141b08..63ddea9 100644
--- a/core/res/res/values-uk-watch/strings.xml
+++ b/core/res/res/values-uk-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Додаток <xliff:g id="NUMBER_0">%1$d</xliff:g> з <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Датчики"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"отримувати доступ до контактів"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"отримувати геодані з годинника"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"отримувати доступ до календаря"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"надсилати та переглядати SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"отримувати доступ до фотографій, медіа-вмісту й інших файлів на годиннику"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"записувати аудіо"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"фотографувати та записувати відео"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"телефонувати та керувати дзвінками"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"отримувати життєві показники з датчиків"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"відображатися як рядок стану"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"отримувати дані з датчиків на тілі (наприклад, з пульсометра)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"отримувати дані про точне місцезнаходження (на основі GPS і мережі)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"отримувати дані про приблизне місцезнаходження (на основі мережі)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"надсилати команди на SIM-карту"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"отримувати повний доступ до мережі"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"керувати власниками профілів і пристроїв"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"змінювати стан WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"отримувати інформацію про стан функції Передавання даних Android"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"вибирати маршрути виводу медіа-вмісту"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"отримувати дані про сеанси встановлення"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"надсилати запити на пакети встановлення"</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK-watch/strings.xml b/core/res/res/values-ur-rPK-watch/strings.xml
index f90af0b..8ba8042 100644
--- a/core/res/res/values-ur-rPK-watch/strings.xml
+++ b/core/res/res/values-ur-rPK-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"ایپ <xliff:g id="NUMBER_0">%1$d</xliff:g> از <xliff:g id="NUMBER_1">%2$d</xliff:g>۔"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"سینسرز"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"اپنے رابطوں تک رسائی حاصل کریں"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"اس گھڑی کے مقام تک رسائی حاصل کریں"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"اپنے کیلنڈر تک رسائی حاصل کریں"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"‏SMS پیغامات بھیجیں اور دیکھیں"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"اپنی گھڑی پر تصاویر، میڈیا اور فائلوں تک رسائی حاصل کریں"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"آڈیو ریکارڈ کریں"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"تصاویر لیں اور ویڈیو ریکارڈ کریں"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"فون کالز کریں اور ان کا نظم کریں"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"اپنی علامات حیات کے متعلق سنسر ڈیٹا تک رسائی حاصل کریں"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"بطور اسٹیٹس بار کام لیں"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"باڈی سینسرز تک رسائی حاصل کریں (جیسے دل کی دھڑکن کے مانیٹرز)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"‏قطعی مقام تک رسائی حاصل کریں (GPS اور نیٹ ورک پر مبنی)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"تخمینی مقام تک رسائی حاصل کریں (نیٹ ورک پر مبنی)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"‏SIM کو ہدایات بھیجیں"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"پورے نیٹ ورک تک رسائی حاصل کریں"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"پروفائل اور آلہ کے مالکان کا نظم کریں"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"‏WiMAX کی حیثیت تبدیل کریں"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"‏Android Beam منتقلی کی صورت حال موصول کریں"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"میڈیا آؤٹ پٹ کی سمت طے کریں"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"انسٹال سیشنز پڑھیں"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"پیکجز انسٹال کرنے کی درخواست کریں"</string>
 </resources>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index aa46949..e6e20f1 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -429,7 +429,7 @@
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"فنگر پرنٹ اسٹور نہیں کیا جا سکتا ہے۔ براہ کرم ایک موجودہ فنگر پرنٹ ہٹائیں۔"</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"فنگر پرنٹ کی میعاد ختم ہوگئی۔ دوبارہ کوشش کریں۔"</string>
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"فنگر پرنٹ کی کارروائی منسوخ ہوگئی۔"</string>
-    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوباہ کوشش کریں۔"</string>
+    <string name="fingerprint_error_lockout" msgid="5536934748136933450">"کافی زیادہ کوششیں کی گئیں۔ بعد میں دوبارہ کوشش کریں۔"</string>
     <string name="fingerprint_error_unable_to_process" msgid="6107816084103552441">"دوبارہ کوشش کریں۔"</string>
     <string name="fingerprint_name_template" msgid="5870957565512716938">"انگلی <xliff:g id="FINGERID">%d</xliff:g>"</string>
   <string-array name="fingerprint_error_vendor">
diff --git a/core/res/res/values-uz-rUZ-watch/strings.xml b/core/res/res/values-uz-rUZ-watch/strings.xml
index 42fe54a..0fe54a1 100644
--- a/core/res/res/values-uz-rUZ-watch/strings.xml
+++ b/core/res/res/values-uz-rUZ-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>dan <xliff:g id="NUMBER_0">%1$d</xliff:g> ilova."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorlar"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirishga ruxsat berish"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"mazkur soatning joylashgan joyini ko‘rishga ruxsat berish"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"taqvim ma’lumotlariga kirish"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS xabarlarni yuborish va ko‘rish"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Soatingizdagi rasmlar, media va fayllarga kirish"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ovoz yozib olish"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"rasmga tushirish va videoga olish"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"asosiy belgilaringiz haqidagi sezgich ma’lumotlaridan foydalanishga ruxsat"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"holat qatorida ko‘rinishi"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"tana sezgichlari (m-n, yurak urishi sensori) ma’lumotlaridan foydalanishga ruxsat"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"aniq joylashuv (GPS va tarmoqqa asoslanib) ma’lumotlaridan foydalanishga ruxsat"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"taxminiy joylashuv (tarmoq asosida) ma’lumotlaridan foydalanishga ruxsat"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIM kartaga buyruqlar yuborish"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"to‘liq tarmoqdan foydalanish ruxsatiga ega"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"profil va qurilma egalarini boshqarish"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX holatini o‘zgartirish"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Android Beam o‘tkazmasi holati haqidagi ma’lumotlarni olish"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"media chiqishni yo‘naltirish"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"o‘rnatish seansi ma’lumotlarini o‘qish"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"paketlarni o‘rnatish so‘rovini yuborish"</string>
 </resources>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 492f3d7..325ad91 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -414,18 +414,18 @@
     <string name="permdesc_nfc" msgid="7120611819401789907">"Ilova qisqa masofali aloqa (NFC) texnologiyasi yordamida NFC yorliqlari, kartalar va o‘qish moslamalari bilan ma’lumot almashishi mumkin."</string>
     <string name="permlab_disableKeyguard" msgid="3598496301486439258">"ekran qulfini o‘chirib qo‘yish"</string>
     <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"Ilovaga ekran qulfini va har qanday parol  yordamidagi xavfsizlik himoyalarini o‘chirishga ruxsat beradi. Masalan, kirish qo‘ng‘irog‘ida telefon ekran qulfini o‘chiradi va qo‘ng‘iroq tugashi bilan qulfni yoqadi."</string>
-    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"barmoq izi sensorini boshqarish"</string>
+    <string name="permlab_manageFingerprint" msgid="5640858826254575638">"barmoq izi skanerini boshqarish"</string>
     <string name="permdesc_manageFingerprint" msgid="178208705828055464">"Ilova foydalanish uchun barmoq izi namunalarini qo‘shish va o‘chirish usullarini qo‘llashi mumkin."</string>
     <string name="permlab_useFingerprint" msgid="3150478619915124905">"barmoq izi sensoridan foydalanish"</string>
     <string name="permdesc_useFingerprint" msgid="9165097460730684114">"Ilova haqiqiylikni tekshirish uchun barmoq izi sensoridan foydalanishi mumkin"</string>
     <string name="fingerprint_acquired_partial" msgid="735082772341716043">"Barmoq izi qisman aniqlandi. Qayta urinib ko‘ring."</string>
     <string name="fingerprint_acquired_insufficient" msgid="4596546021310923214">"Barmoq izi aniqlanmadi. Qayta urinib ko‘ring."</string>
-    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmoq izi sensori kirlangan. Uni tozalab, keyin qayta urinib ko‘ring."</string>
+    <string name="fingerprint_acquired_imager_dirty" msgid="1087209702421076105">"Barmoq izi skaneri kirlangan. Uni tozalab, keyin qayta urinib ko‘ring."</string>
     <string name="fingerprint_acquired_too_fast" msgid="6470642383109155969">"Barmoq juda tez harakatlandi. Qayta urinib ko‘ring."</string>
     <string name="fingerprint_acquired_too_slow" msgid="59250885689661653">"Barmoq juda sekin harakatlandi. Qayta urinib ko‘ring."</string>
   <string-array name="fingerprint_acquired_vendor">
   </string-array>
-    <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi sensori ish holatida emas."</string>
+    <string name="fingerprint_error_hw_not_available" msgid="7955921658939936596">"Barmoq izi skaneri ish holatida emas."</string>
     <string name="fingerprint_error_no_space" msgid="1055819001126053318">"Barmoq izini saqlab bo‘lmadi. Mavjud barmoq izlaridan birini o‘chirib tashlang."</string>
     <string name="fingerprint_error_timeout" msgid="3927186043737732875">"Barmoq izini aniqlash vaqti tugab qoldi. Qayta urinib ko‘ring."</string>
     <string name="fingerprint_error_canceled" msgid="4402024612660774395">"Barmoq izi tekshiruvi bekor qilindi."</string>
@@ -676,7 +676,7 @@
     <string name="lockscreen_transport_stop_description" msgid="5907083260651210034">"To‘xtatish"</string>
     <string name="lockscreen_transport_rew_description" msgid="6944412838651990410">"Orqaga o‘tkazish"</string>
     <string name="lockscreen_transport_ffw_description" msgid="42987149870928985">"Oldinga o‘tkazish"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"Faqat favqulodda chaqiruvlar"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"Faqat favqulodda qo‘ng‘iroqlar"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"Tarmoq qulflangan"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-karta PUK kod bilan qulflangan."</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"Foydalanuvchi qo‘llanmasiga qarang yoki Abonentlarni qo‘llab-quvvatlash markaziga murojaat qiling."</string>
@@ -1024,9 +1024,9 @@
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USB orqali rasm o‘tkazish"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB orqali MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB jihozga ulangan"</string>
-    <string name="usb_notification_message" msgid="7347368030849048437">"Boshqa variantlar"</string>
-    <string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozlikni tuzatish"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing"</string>
+    <string name="usb_notification_message" msgid="7347368030849048437">"Sozlash uchun bosing."</string>
+    <string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"O‘chirib qo‘yish uchun bosing."</string>
     <string name="select_input_method" msgid="8547250819326693584">"Klaviaturani o‘zgartirish"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Klaviaturani tanlash"</string>
     <string name="show_ime" msgid="9157568568695230830">"Kiritish usulini ko‘rish"</string>
diff --git a/core/res/res/values-vi-watch/strings.xml b/core/res/res/values-vi-watch/strings.xml
index 634d890..8bfd3df 100644
--- a/core/res/res/values-vi-watch/strings.xml
+++ b/core/res/res/values-vi-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Ứng dụng <xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Cảm biến"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"truy cập danh bạ của bạn"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"truy cập vị trí của đồng hồ này"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"truy cập lịch của bạn"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"gửi và xem tin nhắn SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"truy cập ảnh, phương tiện và tệp trên đồng hồ của bạn"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ghi âm"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"chụp ảnh và quay video"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"thực hiện và quản lý cuộc gọi điện thoại"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"truy cập dữ liệu cảm biến về dấu hiệu sinh tồn của bạn"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"trở thành thanh trạng thái"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"truy cập cảm biến cơ thể (như máy đo nhịp tim)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"truy cập vị trí chính xác (dựa vào mạng và GPS)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"truy cập vị trí gần đúng (dựa vào mạng)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"gửi lệnh đến SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"có quyền truy cập mạng đầy đủ"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"quản lý chủ sở hữu thiết bị và hồ sơ"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"thay đổi trạng thái WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"nhận trạng thái chuyển của Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"định tuyến thiết bị ra phương tiện"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"đọc phiên cài đặt"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"yêu cầu gói cài đặt"</string>
 </resources>
diff --git a/core/res/res/values-zh-rCN-watch/strings.xml b/core/res/res/values-zh-rCN-watch/strings.xml
index 8864701..f336907 100644
--- a/core/res/res/values-zh-rCN-watch/strings.xml
+++ b/core/res/res/values-zh-rCN-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"应用:<xliff:g id="NUMBER_0">%1$d</xliff:g> / <xliff:g id="NUMBER_1">%2$d</xliff:g>。"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"传感器"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"使用您的通讯录"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"访问此手表的位置信息"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"访问您的日历"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"发送和查看短信"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"访问您手表中的照片、媒体和文件"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"录制音频"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"拍摄照片和录制视频"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"拨打电话和管理通话"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"访问与您的生命体征相关的传感器数据"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"用作状态栏"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"访问身体传感器(如心率监测器)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"访问确切位置信息(以 GPS 和网络为依据)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"访问大致位置信息(以网络为依据)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"向 SIM 卡发送命令"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"拥有完全的网络访问权限"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"管理个人资料和设备所有者"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"更改 WiMAX 状态"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"接收 Android Beam 的传输状态"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"更改媒体输出线路"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"读取安装会话"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"请求安装文件包"</string>
 </resources>
diff --git a/core/res/res/values-zh-rHK-watch/strings.xml b/core/res/res/values-zh-rHK-watch/strings.xml
index 356e853..b5ecb08 100644
--- a/core/res/res/values-zh-rHK-watch/strings.xml
+++ b/core/res/res/values-zh-rHK-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"應用程式 (<xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>)"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"感應器"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"存取您的通訊錄"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"存取此手錶的位置"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"存取您的日曆"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"傳送和查看短訊"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"存取手錶上的相片、媒體和檔案"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"錄製語音"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"拍攝和錄製影片"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"撥打電話及管理通話"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"存取與您生命體徵相關的感應器資料"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"成為狀態列"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"存取身體感應器 (例如心跳監測器)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"存取精確位置 (根據 GPS 和網絡)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"存取約略位置 (根據網絡)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"發送指令至 SIM 卡"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"擁有全面網絡存取權"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"管理個人檔案和裝置擁有者"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"變更 WiMAX 狀態"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"接收 Android Beam 的傳送狀態"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"轉送媒體輸出"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"讀取安裝工作階段"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"要求安裝套件"</string>
 </resources>
diff --git a/core/res/res/values-zh-rTW-watch/strings.xml b/core/res/res/values-zh-rTW-watch/strings.xml
index 20ef6ba..79fb99d 100644
--- a/core/res/res/values-zh-rTW-watch/strings.xml
+++ b/core/res/res/values-zh-rTW-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"應用程式 <xliff:g id="NUMBER_0">%1$d</xliff:g>/<xliff:g id="NUMBER_1">%2$d</xliff:g>。"</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"感應器"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"存取您的聯絡人"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"存取這個手錶的位置資訊"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"存取您的日曆"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"傳送及查看簡訊"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"存取手錶上的相片、媒體和檔案"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"錄音"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"拍照及錄製影片"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"撥打電話及管理通話"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"存取生命徵象相關感應器資料"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"用作狀態列"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"存取人體感測器 (例如心跳速率監測器)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"存取精確位置 (以 GPS 和網路為依據)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"存取概略位置 (以網路為依據)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"傳送指令到 SIM 卡"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"擁有完整的網路存取權"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"管理個人資料和裝置擁有者"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"變更 WiMAX 狀態"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"接收 Android Beam 的傳輸狀態"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"轉送媒體輸出"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"讀取安裝工作階段"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"索取安裝套件"</string>
 </resources>
diff --git a/core/res/res/values-zu-watch/strings.xml b/core/res/res/values-zu-watch/strings.xml
index 22b8af7..e9121b9 100644
--- a/core/res/res/values-zu-watch/strings.xml
+++ b/core/res/res/values-zu-watch/strings.xml
@@ -21,48 +21,26 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Uhlelo lokusebenza olungu-<xliff:g id="NUMBER_0">%1$d</xliff:g> kokungu-<xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
-    <!-- no translation found for permgrouplab_sensors (202675452368612754) -->
-    <skip />
-    <!-- no translation found for permgrouplab_contactswear (2340286500790908344) -->
-    <skip />
-    <!-- no translation found for permgrouplab_locationwear (6275317222482780209) -->
-    <skip />
-    <!-- no translation found for permgrouplab_calendarwear (441900844045065081) -->
-    <skip />
-    <!-- no translation found for permgrouplab_smswear (6849506550342974220) -->
-    <skip />
-    <!-- no translation found for permgrouplab_storagewear (1003807594193602313) -->
-    <skip />
-    <!-- no translation found for permgrouplab_microphonewear (1047561180980891136) -->
-    <skip />
-    <!-- no translation found for permgrouplab_camerawear (4543951283103407017) -->
-    <skip />
-    <!-- no translation found for permgrouplab_phonewear (134365036753766126) -->
-    <skip />
-    <!-- no translation found for permgrouplab_sensorswear (1429324744329327663) -->
-    <skip />
-    <!-- no translation found for permlab_statusBarServicewear (2469402818964691034) -->
-    <skip />
-    <!-- no translation found for permlab_bodySensorswear (7857941041202791873) -->
-    <skip />
-    <!-- no translation found for permlab_accessFineLocationwear (5584423486924377563) -->
-    <skip />
-    <!-- no translation found for permlab_accessCoarseLocationwear (5880746016230166090) -->
-    <skip />
-    <!-- no translation found for permlab_sim_communicationwear (1899198085342781874) -->
-    <skip />
-    <!-- no translation found for permlab_createNetworkSocketswear (6467042386273822913) -->
-    <skip />
-    <!-- no translation found for permlab_manageProfileAndDeviceOwnerswear (7313340516937821847) -->
-    <skip />
-    <!-- no translation found for permlab_changeWimaxStatewear (3828470843939853744) -->
-    <skip />
-    <!-- no translation found for permlab_handoverStatuswear (4835786819716499249) -->
-    <skip />
-    <!-- no translation found for permlab_route_media_outputwear (8737024341474587192) -->
-    <skip />
-    <!-- no translation found for permlab_readInstallSessionswear (9059478058685861989) -->
-    <skip />
-    <!-- no translation found for permlab_requestInstallPackageswear (4982025836783539503) -->
-    <skip />
+    <string name="permgrouplab_sensors" msgid="202675452368612754">"Izinzwa"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"finyelela koxhumana nabo"</string>
+    <string name="permgrouplab_locationwear" msgid="6275317222482780209">"finyelela indawo yaleli washi"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"finyelela kukhalenda yakho"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"thumela uphinde ubuke imilayezo ye-SMS"</string>
+    <string name="permgrouplab_storagewear" msgid="1003807594193602313">"finyelela izithombe, imidiya, namafayela kuwashi lakho"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"rekhoda ividiyo"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"thatha izithombe uphinde urekhode ividiyo"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"yenza uphinde uphathe amakholi wefoni"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"finyelela idatha yenzwa mayelana nezimpawu zakho ezibalulekile"</string>
+    <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"yiba yibha yesimo"</string>
+    <string name="permlab_bodySensorswear" msgid="7857941041202791873">"finyelela kuzinzwa zomzimba (ezifana neziqaphi zokulinganisela inhliziyo)"</string>
+    <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"finyelela indawo enembile (i-GPS nesuselwa kunethiwekhi)"</string>
+    <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"finyelela kundawo elinganiselwe (esuselwa kunethiwekhi)"</string>
+    <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"thumela imilayezo ku-SIM"</string>
+    <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"iba nokufinyelela okugcwele kwenethiwekhi"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"phatha iphrofayela nabanikazi bedivayisi"</string>
+    <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"shintsha isimo se-WiMAX"</string>
+    <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"thola isimo sokudlulisa se-Android Beam"</string>
+    <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"yenza umzila ukukhipha kwemidiya"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"funda izikhathi zokufaka"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"cela amaphakheji wokufaka"</string>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 61af6c5..48bfe28 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -639,6 +639,8 @@
         <attr name="imageButtonStyle" format="reference" />
         <!-- The style resource to use for an ImageButton that is an image well. -->
         <attr name="imageWellStyle" format="reference" />
+        <!-- Default menu-style ListView style. -->
+        <attr name="listMenuViewStyle" format="reference" />
         <!-- Default ListView style. -->
         <attr name="listViewStyle" format="reference" />
         <!-- ListView with white background. -->
@@ -1818,6 +1820,7 @@
         <enum name="KEYCODE_MEDIA_SKIP_BACKWARD" value="273" />
         <enum name="KEYCODE_MEDIA_STEP_FORWARD" value="274" />
         <enum name="KEYCODE_MEDIA_STEP_BACKWARD" value="275" />
+        <enum name="KEYCODE_SOFT_SLEEP" value="276" />
     </attr>
 
     <!-- ***************************************************************** -->
@@ -3784,6 +3787,8 @@
         <attr name="itemIconDisabledAlpha" format="float" />
         <!-- Whether space should be reserved in layout when an icon is missing. -->
         <attr name="preserveIconSpacing" format="boolean" />
+        <!-- Drawable for the arrow icon indicating a particular item is a submenu. -->
+        <attr name="subMenuArrow" format="reference" />
     </declare-styleable>
     <declare-styleable name="IconMenuView">
         <!-- Defines the height of each row. -->
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4531f75..091d57f 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -24,7 +24,7 @@
     <!-- The overall theme to use for an activity.  Use with either the
          application tag (to supply a default theme for all activities) or
          the activity tag (to supply a specific theme for that activity).
-    
+
          <p>This automatically sets
          your activity's Context to use this theme, and may also be used
          for "starting" animations prior to the activity being launched (to
@@ -39,7 +39,7 @@
          tag (to supply a specific label for that component).  It may also be
          used with the intent-filter tag to supply a label to show to the
          user when an activity is being selected based on a particular Intent.
-    
+
          <p>The given label will be used wherever the user sees information
          about its associated component; for example, as the name of a
          main activity that is displayed in the launcher.  You should
@@ -47,7 +47,7 @@
          it can be localized, however it is also allowed to supply a plain
          string for quick and dirty programming. -->
     <attr name="label" format="reference|string" />
-    
+
     <!-- A Drawable resource providing a graphical representation of its
          associated item.  Use with the
          application tag (to supply a default icon for all application
@@ -55,7 +55,7 @@
          tag (to supply a specific icon for that component).  It may also be
          used with the intent-filter tag to supply an icon to show to the
          user when an activity is being selected based on a particular Intent.
-    
+
          <p>The given icon will be used to display to the user a graphical
          representation of its associated component; for example, as the icon
          for main activity that is displayed in the launcher.  This must be
@@ -95,15 +95,15 @@
 
     <!-- Name of the activity to be launched to manage application's space on
          device. The specified activity gets automatically launched when the
-         application's space needs to be managed and is usually invoked 
+         application's space needs to be managed and is usually invoked
          through user actions. Applications can thus provide their own custom
          behavior for managing space for various scenarios like out of memory
          conditions. This is an optional attribute and
-         applications can choose not to specify a default activity to 
+         applications can choose not to specify a default activity to
          manage space. -->
     <attr name="manageSpaceActivity" format="string" />
 
-    <!-- Option to let applications specify that user data can/cannot be 
+    <!-- Option to let applications specify that user data can/cannot be
          cleared. This flag is turned on by default.
          <em>This attribute is usable only by applications
          included in the system image. Third-party apps cannot use it.</em> -->
@@ -122,31 +122,31 @@
          kind of application can not be installed without the
          INSTALL_ALLOW_TEST flag, which means only through adb install.  -->
     <attr name="testOnly" format="boolean" />
-    
+
     <!-- A unique name for the given item.  This must use a Java-style naming
          convention to ensure the name is unique, for example
-         "com.mycompany.MyName". -->  
+         "com.mycompany.MyName". -->
     <attr name="name" format="string" />
-    
+
     <!-- Specify a permission that a client is required to have in order to
     	 use the associated object.  If the client does not hold the named
     	 permission, its request will fail.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="permission" format="string" />
-    
+
     <!-- A specific {@link android.R.attr#permission} name for read-only
          access to a {@link android.content.ContentProvider}.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="readPermission" format="string" />
-    
+
     <!-- A specific {@link android.R.attr#permission} name for write
          access to a {@link android.content.ContentProvider}.  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions. -->
     <attr name="writePermission" format="string" />
-    
+
     <!-- If true, the {@link android.content.Context#grantUriPermission
          Context.grantUriPermission} or corresponding Intent flags can
          be used to allow others to access specific URIs in the content
@@ -156,7 +156,7 @@
          Context.revokeUriPermission} when URIs are deleted from your
          provider.-->
     <attr name="grantUriPermissions" format="boolean" />
-    
+
     <!-- Characterizes the potential risk implied in a permission and
          indicates the procedure the system should follow when determining
          whether to grant the permission to an application requesting it. {@link
@@ -257,7 +257,7 @@
          with.  The group must have been defined with the
          {@link android.R.styleable#AndroidManifestPermissionGroup permission-group} tag. -->
     <attr name="permissionGroup" format="string" />
-    
+
     <!-- Specify the name of a user ID that will be shared between multiple
          packages.  By default, each package gets its own unique user-id.
          By setting this value on two or more packages, each of these packages
@@ -265,13 +265,13 @@
          in the same process.  Note that for them to actually get the same
          user ID, they must also be signed with the same signature. -->
     <attr name="sharedUserId" format="string" />
-    
+
     <!-- Specify a label for the shared user UID of this package.  This is
          only used if you have also used android:sharedUserId.  This must
          be a reference to a string resource; it can not be an explicit
          string. -->
     <attr name="sharedUserLabel" format="reference" />
-    
+
     <!-- Internal version code.  This is the number used to determine whether
          one version is more recent than another: it has no other meaning than
          that higher numbers are more recent.  You could use this number to
@@ -279,7 +279,7 @@
          number, simply increase it by one each time a new version is
          released, or define it however else you want, as long as each
          successive version has a higher number.  This is not a version
-         number generally shown to the user, that is usually supplied 
+         number generally shown to the user, that is usually supplied
          with {@link android.R.attr#versionName}.  When an app is delivered
          as multiple split APKs, each APK must have the exact same versionCode. -->
     <attr name="versionCode" format="integer" />
@@ -296,7 +296,7 @@
          is used for no other purpose than display to the user; the actual
          significant version number is given by {@link android.R.attr#versionCode}. -->
     <attr name="versionName" format="string" />
-    
+
     <!-- Flag to control special persistent mode of an application.  This should
          not normally be used by applications; it requires that the system keep
          your application running at all times. -->
@@ -309,7 +309,7 @@
     <!-- Flag indicating whether the application can be debugged, even when
          running on a device that is running in user mode. -->
     <attr name="debuggable" format="boolean" />
-    
+
     <!-- Flag indicating whether the application requests the VM to operate in
          the safe mode.  -->
     <attr name="vmSafeMode" format="boolean" />
@@ -367,7 +367,7 @@
          Use with the application tag (to supply a default process for all
          application components), or with the activity, receiver, service,
          or provider tag (to supply a specific icon for that component).
-    
+
          <p>Application components are normally run in a single process that
          is created for the entire application.  You can use this tag to modify
          where they run.  If the process name begins with a ':' character,
@@ -378,12 +378,12 @@
          provided that you have permission to do so, allowing multiple
          applications to share one process to reduce resource usage. -->
     <attr name="process" format="string" />
-    
+
     <!-- Specify a task name that activities have an "affinity" to.
          Use with the application tag (to supply a default affinity for all
          activities in the application), or with the activity tag (to supply
          a specific affinity for that component).
-    
+
          <p>The default value for this attribute is the same as the package
          name, indicating that all activities in the manifest should generally
          be considered a single "application" to the user.  You can use this
@@ -392,13 +392,13 @@
          task from the user's perspective, or using an empty string for
          activities that have no affinity to a task. -->
     <attr name="taskAffinity" format="string" />
-    
+
     <!-- Specify that an activity can be moved out of a task it is in to
          the task it has an affinity for when appropriate.  Use with the
          application tag (to supply a default for all activities in the
          application), or with an activity tag (to supply a specific
          setting for that component).
-    
+
          <p>Normally when an application is started, it is associated with
          the task of the activity that started it and stays there for its
          entire lifetime.  You can use the allowTaskReparenting feature to force an
@@ -422,17 +422,17 @@
          applications' processes. On devices that support multiple instruction sets,
          this implies the code might be loaded into a process that's using any of the devices
          supported instruction sets.
-         
+
          <p> The system might treat such applications specially, for eg., by
          extracting the application's native libraries for all supported instruction
          sets or by compiling the application's dex code for all supported instruction
          sets. -->
     <attr name="multiArch" format ="boolean" />
-    
+
     <!-- Specify whether a component is allowed to have multiple instances
          of itself running in different processes.  Use with the activity
          and provider tags.
-    
+
          <p>Normally the system will ensure that all instances of a particular
          component are only running in a single process.  You can use this
          attribute to disable that behavior, allowing the system to create
@@ -441,28 +441,28 @@
          of a provider can be created in each client process, allowing them
          to be used without performing IPC.  -->
     <attr name="multiprocess" format="boolean" />
-    
+
     <!-- Specify whether an activity should be finished when its task is
          brought to the foreground by relaunching from the home screen.
-         
+
          <p>If both this option and {@link android.R.attr#allowTaskReparenting} are
          specified, the finish trumps the affinity: the affinity will be
          ignored and the activity simply finished. -->
     <attr name="finishOnTaskLaunch" format="boolean" />
-    
+
     <!-- Specify whether an activity should be finished when a "close system
          windows" request has been made.  This happens, for example, when
          the home key is pressed, when the device is locked, when a system
          dialog showing recent applications is displayed, etc. -->
     <attr name="finishOnCloseSystemDialogs" format="boolean" />
-    
+
     <!-- Specify whether an activity's task should be cleared when it
          is re-launched from the home screen.  As a result, every time the
          user starts the task, they will be brought to its root activity,
          regardless of whether they used BACK or HOME to last leave it.
          This flag only applies to activities that
          are used to start the root of a new task.
-         
+
          <p>An example of the use of this flag would be for the case where
          a user launches activity A from home, and from there goes to
          activity B.  They now press home, and then return to activity A.
@@ -471,7 +471,7 @@
          then upon going to the background all of the tasks on top of it (B
          in this case) are removed, so when the user next returns to A they
          will restart at its original activity.
-         
+
          <p>When this option is used in conjunction with
          {@link android.R.attr#allowTaskReparenting}, the allowTaskReparenting trumps the
          clear.  That is, all activities above the root activity of the
@@ -479,30 +479,30 @@
          to the task they are associated with, otherwise they will simply
          be dropped as described here. -->
     <attr name="clearTaskOnLaunch" format="boolean" />
-    
+
     <!-- Specify whether an activity should be kept in its history stack.
          If this attribute is set, then as soon as the user navigates away
          from the activity it will be finished and they will no longer be
          able to return to it. -->
     <attr name="noHistory" format="boolean" />
-    
+
     <!-- Specify whether an acitivty's task state should always be maintained
          by the system, or if it is allowed to reset the task to its initial
          state in certain situations.
-         
+
          <p>Normally the system will reset a task (remove all activities from
          the stack and reset the root activity) in certain situations when
          the user re-selects that task from the home screen.  Typically this
          will be done if the user hasn't visited that task for a certain
          amount of time, such as 30 minutes.
-         
+
          <p>By setting this attribute, the user will always return to your
          task in its last state, regardless of how they get there.  This is
          useful, for example, in an application like the web browser where there
          is a lot of state (such as multiple open tabs) that the application
          would not like to lose. -->
     <attr name="alwaysRetainTaskState" format="boolean" />
-    
+
     <!-- Indicates that an Activity does not need to have its freeze state
          (as returned by {@link android.app.Activity#onSaveInstanceState}
          retained in order to be restarted.  Generally you use this for activities
@@ -512,7 +512,7 @@
          it normally would.  Instead, the next time the user navigates to
          it its {@link android.app.Activity#onCreate} method will be called
          with a null icicle, just like it was starting for the first time.
-         
+
          <p>This is used by the Home activity to make sure it does not get
          removed if it crashes for some reason. -->
     <attr name="stateNotNeeded" format="boolean" />
@@ -539,11 +539,11 @@
          in order to avoid conflicts.  Typically this name is the same
          as the class implementation describing the provider's data structure. -->
     <attr name="authorities" format="string" />
-    
+
     <!-- Flag indicating whether this content provider would like to
          participate in data synchronization. -->
     <attr name="syncable" format="boolean" />
-    
+
     <!-- Flag declaring this activity to be 'immersive'; immersive activities
          should not be interrupted with other activities or notifications. -->
     <attr name="immersive" format="boolean" />
@@ -555,7 +555,7 @@
          The value is a simple integer, with higher numbers being
          initialized first. -->
     <attr name="initOrder" format="integer" />
-    
+
     <!-- Specify the relative importance or ability in handling a particular
          Intent.  For receivers, this controls the order in which they are
          executed to receive a broadcast (note that for
@@ -564,18 +564,18 @@
          Intent; when multiple activities match an intent and have different
          priorities, only those with the higher priority value will be
          considered a match.
-         
+
          <p>Only use if you really need to impose some specific
          order in which the broadcasts are received, or want to forcibly
          place an activity to always be preferred over others.  The value is a
          single integer, with higher numbers considered to be better. -->
     <attr name="priority" format="integer" />
-    
+
     <!-- Specify how an activity should be launched.  See the
          <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
          Stack</a> document for important information on how these options impact
          the behavior of your application.
-         
+
          <p>If this attribute is not specified, <code>standard</code> launch
          mode will be used.  Note that the particular launch behavior can
          be changed in some ways at runtime through the
@@ -612,19 +612,19 @@
             <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
             Stack</a> document for more details about tasks.-->
         <enum name="singleTask" value="2" />
-        <!-- Only allow one instance of this activity to ever be 
-            running.  This activity gets a unique task with only itself running 
-            in it; if it is ever launched again with the same Intent, then that 
-            task will be brought forward and its 
+        <!-- Only allow one instance of this activity to ever be
+            running.  This activity gets a unique task with only itself running
+            in it; if it is ever launched again with the same Intent, then that
+            task will be brought forward and its
             {@link android.app.Activity#onNewIntent Activity.onNewIntent()}
-            method called.  If this 
-            activity tries to start a new activity, that new activity will be 
+            method called.  If this
+            activity tries to start a new activity, that new activity will be
             launched in a separate task.  See the
             <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
             Stack</a> document for more details about tasks.-->
         <enum name="singleInstance" value="3" />
     </attr>
-    
+
     <!-- Specify the orientation an activity should be run in.  If not
          specified, it will run in the current preferred orientation
          of the screen.
@@ -638,7 +638,7 @@
              if this activity is the bottom of a task. If the user
              explicitly turned off sensor based orientation through settings
              sensor based device rotation will be ignored. If not by default
-             sensor based orientation will be taken into account and the 
+             sensor based orientation will be taken into account and the
              orientation will changed based on how the user rotates the device.
              Corresponds to
              {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}. -->
@@ -726,19 +726,19 @@
              {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LOCKED}. -->
         <enum name="locked" value="14" />
     </attr>
-    
+
     <!-- Specify one or more configuration changes that the activity will
          handle itself.  If not specified, the activity will be restarted
          if any of these configuration changes happen in the system.  Otherwise,
          the activity will remain running and its
          {@link android.app.Activity#onConfigurationChanged Activity.onConfigurationChanged}
          method called with the new configuration.
-         
+
          <p>Note that all of these configuration changes can impact the
          resource values seen by the application, so you will generally need
          to re-retrieve all resources (including view layouts, drawables, etc)
          to correctly handle any configuration change.
-         
+
          <p>These values must be kept in sync with those in
          {@link android.content.pm.ActivityInfo} and
          include/utils/ResourceTypes.h. -->
@@ -804,18 +804,18 @@
 
     <!-- Descriptive text for the associated data. -->
     <attr name="description" format="reference" />
-    
+
     <!-- The name of the application package that an Instrumentation object
          will run against. -->
     <attr name="targetPackage" format="string" />
-    
+
     <!-- Flag indicating that an Instrumentation class wants to take care
          of starting/stopping profiling itself, rather than relying on
          the default behavior of profiling the complete time it is running.
          This allows it to target profiling data at a specific set of
          operations. -->
     <attr name="handleProfiling" format="boolean" />
-    
+
     <!-- Flag indicating that an Instrumentation class should be run as a
          functional test. -->
     <attr name="functionalTest" format="boolean" />
@@ -1069,8 +1069,7 @@
 
          <p>NOTE: The value of {@link android.R.attr#screenOrientation} will be ignored for
          resizeable activities as the system doesn't support fixed orientation on a resizeable
-         activity.
-         @hide -->
+         activity. -->
     <attr name="resizeableActivity" format="boolean" />
 
     <!-- This value indicates how tasks rooted at this activity will behave in lockTask mode.
@@ -1271,7 +1270,7 @@
          features in your package (or other packages).  See the
          <a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>
          document for more information on permissions.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermission" parent="AndroidManifest">
@@ -1290,15 +1289,15 @@
         <attr name="protectionLevel" />
         <attr name="permissionFlags" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-group</code> tag declares a logical grouping of
          related permissions.
-         
+
          <p>Note that this tag does not declare a permission itself, only
          a namespace in which further permissions can be placed.  See
          the {@link #AndroidManifestPermission &lt;permission&gt;} tag for
          more information.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermissionGroup" parent="AndroidManifest">
@@ -1316,7 +1315,7 @@
         <attr name="permissionGroupFlags" />
         <attr name="priority" />
     </declare-styleable>
-    
+
     <!-- The <code>permission-tree</code> tag declares the base of a tree of
          permission values: it declares that this package has ownership of
          the given permission name, as well as all names underneath it
@@ -1324,12 +1323,12 @@
          {@link android.content.pm.PackageManager#addPermission
          PackageManager.addPermission()} method to dynamically add new
          permissions under this tree.
-         
+
          <p>Note that this tag does not declare a permission itself, only
          a namespace in which further permissions can be placed.  See
          the {@link #AndroidManifestPermission &lt;permission&gt;} tag for
          more information.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestPermissionTree" parent="AndroidManifest">
@@ -1346,7 +1345,7 @@
         <attr name="banner" />
         <attr name="logo" />
     </declare-styleable>
-    
+
     <!-- The <code>uses-permission</code> tag requests a
          {@link #AndroidManifestPermission &lt;permission&gt;} that the containing
          package must be granted in order for it to operate correctly. For runtime
@@ -1359,7 +1358,7 @@
          document for more information on permissions.  Also available is a
          {@link android.Manifest.permission list of permissions} included
          with the base platform.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestUsesPermission" parent="AndroidManifest">
@@ -1436,7 +1435,7 @@
 
     <!-- The <code>uses-sdk</code> tag describes the SDK features that the
          containing package must be running on to operate correctly.
-         
+
          <p>This appears as a child tag of the root
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestUsesSdk" parent="AndroidManifest">
@@ -1464,7 +1463,7 @@
              incompatibility with them. -->
         <attr name="maxSdkVersion" />
     </declare-styleable>
-    
+
     <!-- The <code>library</code> tag declares that this apk is providing itself
          as a shared library for other applications to use.  It can only be used
          with apks that are built in to the system image.  Other apks can link to
@@ -1483,7 +1482,7 @@
     <!-- The <code>uses-libraries</code> specifies a shared library that this
          package requires to be linked against.  Specifying this flag tells the
          system to include this library's code in your class loader.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifestApplication application} tag. -->
     <declare-styleable name="AndroidManifestUsesLibrary" parent="AndroidManifestApplication">
@@ -1498,7 +1497,7 @@
               dynamically at runtime. -->
         <attr name="required" />
     </declare-styleable>
-    
+
     <!-- The <code>supports-screens</code> specifies the screen dimensions an
          application supports.  By default a modern application supports all
          screen sizes and must explicitly disable certain screen sizes here;
@@ -1506,7 +1505,7 @@
          (HVGA) screen size.  Note that screen size is a separate axis from
          density, and is determined as the available pixels to an application
          after density scaling has been applied.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifest manifest} tag. -->
     <declare-styleable name="AndroidManifestSupportsScreens" parent="AndroidManifest">
@@ -1609,7 +1608,7 @@
          {@link android.content.ContentProvider} class that is available
          as part of the package's application components, supplying structured
          access to data managed by the application.
-         
+
          <p>This appears as a child tag of the
          {@link #AndroidManifestApplication application} tag. -->
     <declare-styleable name="AndroidManifestProvider" parent="AndroidManifestApplication">
@@ -1641,7 +1640,7 @@
         <attr name="exported" />
         <attr name="singleUser" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>grant-uri-permission</code> tag, a child of the
          {@link #AndroidManifestProvider provider} tag, describing a specific
@@ -1658,7 +1657,7 @@
         <attr name="pathPrefix" format="string" />
         <!-- Specify a URI path that matches a simple pattern, as per
              {@link android.os.PatternMatcher} with
-             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}. 
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
              Note that because '\' is used as an escape character when
              reading the string from XML (before it is parsed as a pattern),
              you will need to double-escape: for example a literal "*" would
@@ -1667,7 +1666,7 @@
              write if constructing the string in Java code. -->
         <attr name="pathPattern" format="string" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>path-permission</code> tag, a child of the
          {@link #AndroidManifestProvider provider} tag, describing a permission
@@ -1681,13 +1680,13 @@
         <attr name="readPermission" />
         <attr name="writePermission" />
     </declare-styleable>
-    
+
     <!-- The <code>service</code> tag declares a
          {@link android.app.Service} class that is available
          as part of the package's application components, implementing
          long-running background operations or a rich communication API
          that can be called by other packages.
-         
+
          <p>Zero or more {@link #AndroidManifestIntentFilter intent-filter}
          tags can be included inside of a service, to specify the Intents
          that can connect with it.  If none are specified, the service can
@@ -1724,13 +1723,13 @@
         <attr name="isolatedProcess" format="boolean" />
         <attr name="singleUser" />
     </declare-styleable>
-    
+
     <!-- The <code>receiver</code> tag declares an
          {@link android.content.BroadcastReceiver} class that is available
          as part of the package's application components, allowing the
          application to receive actions or data broadcast by other
          applications even if it is not currently running.
-         
+
          <p>Zero or more {@link #AndroidManifestIntentFilter intent-filter}
          tags can be included inside of a receiver, to specify the Intents
          it will receive.  If none are specified, the receiver will only
@@ -1826,7 +1825,6 @@
         <attr name="autoRemoveFromRecents" />
         <attr name="relinquishTaskIdentity" />
         <attr name="resumeWhilePausing" />
-        <!-- @hide -->
         <attr name="resizeableActivity" />
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
@@ -1878,7 +1876,7 @@
          data by the system.  You may supply the data through either the
          <code>value</code> or <code>resource</code> attribute; if both
          are given, then <code>resource</code> will be used.
-         
+
          <p>It is highly recommended that you avoid supplying related data as
          multiple separate meta-data entries.  Instead, if you have complex
          data to associate with a component, then use the <code>resource</code>
@@ -1907,22 +1905,22 @@
              Bundle through {@link android.os.Bundle#getInt Bundle.getInt}. -->
         <attr name="resource" format="reference" />
     </declare-styleable>
-    
+
     <!-- The <code>intent-filter</code> tag is used to construct an
          {@link android.content.IntentFilter} object that will be used
          to determine which component can handle a particular
          {@link android.content.Intent} that has been given to the system.
          It can be used as a child of the
          {@link #AndroidManifestActivity activity},
-         {@link #AndroidManifestReceiver receiver} and 
+         {@link #AndroidManifestReceiver receiver} and
          {@link #AndroidManifestService service}
          tags.
-         
+
          <p> Zero or more {@link #AndroidManifestAction action},
          {@link #AndroidManifestCategory category}, and/or
          {@link #AndroidManifestData data} tags should be
          included inside to describe the contents of the filter.
-         
+
          <p> The optional label and icon attributes here are used with
          an activity to supply an alternative description of that activity
          when it is being started through an Intent matching this filter. -->
@@ -1935,7 +1933,7 @@
         <attr name="priority" />
         <attr name="autoVerify" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>action</code> tag, a child of the
          {@link #AndroidManifestIntentFilter intent-filter} tag.
@@ -1950,7 +1948,7 @@
              package name. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>data</code> tag, a child of the
          {@link #AndroidManifestIntentFilter intent-filter} tag, describing
@@ -2022,7 +2020,7 @@
         <!-- Specify a URI path that matches a simple pattern, as per
              {@link android.content.IntentFilter#addDataPath
              IntentFilter.addDataPath()} with
-             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}. 
+             {@link android.os.PatternMatcher#PATTERN_SIMPLE_GLOB}.
              Note that because '\' is used as an escape character when
              reading the string from XML (before it is parsed as a pattern),
              you will need to double-escape: for example a literal "*" would
@@ -2031,10 +2029,10 @@
              write if constructing the string in Java code. -->
         <attr name="pathPattern" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>category</code> tag, a child of the
-         {@link #AndroidManifestIntentFilter intent-filter} tag. 
+         {@link #AndroidManifestIntentFilter intent-filter} tag.
          See {@link android.content.IntentFilter#addCategory} for
          more information. -->
     <declare-styleable name="AndroidManifestCategory" parent="AndroidManifestIntentFilter">
@@ -2046,7 +2044,7 @@
              package name. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>instrumentation</code> tag, a child of the root
          {@link #AndroidManifest manifest} tag. -->
@@ -2065,7 +2063,7 @@
         <attr name="handleProfiling" />
         <attr name="functionalTest" />
     </declare-styleable>
-    
+
     <!-- Attributes that can be supplied in an AndroidManifest.xml
          <code>screen</code> tag, a child of <code>compatible-screens</code>,
          which is itself a child of the root
@@ -2162,14 +2160,14 @@
             {@link android.content.Intent#setComponent Intent.setComponent()}. -->
         <attr name="targetClass" format="string" />
     </declare-styleable>
-    
+
     <!-- A category to add to an Intent, as per
             {@link android.content.Intent#addCategory Intent.addCategory()}. -->
     <declare-styleable name="IntentCategory" parent="Intent">
         <!-- Required name of the category. -->
         <attr name="name" />
     </declare-styleable>
-    
+
     <!-- An extra data value to place into a an extra/name value pair held
             in a Bundle, as per {@link android.os.Bundle}. -->
     <declare-styleable name="Extra" parent="Intent">
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ef4e261..e43a8d3 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -170,6 +170,21 @@
          so that applications can still use their own mechanisms. -->
     <bool name="config_enableAutoPowerModes">false</bool>
 
+    <!-- The threshold angle for any motion detection in auto-power save modes.
+         In hundreths of a degree. -->
+    <integer name="config_autoPowerModeThresholdAngle">200</integer>
+
+    <!-- The sensor id of an "any motion" sensor used in auto-power save modes.
+         0 indicates this sensor is not available. -->
+    <integer name="config_autoPowerModeAnyMotionSensor">0</integer>
+
+    <!-- If an any motion sensor is not available, prefer the wrist tilt detector over the
+         SMD. -->
+    <bool name="config_autoPowerModePreferWristTilt">false</bool>
+
+    <!-- If a location should be pre-fetched when going into device idle. -->
+    <bool name="config_autoPowerModePrefetchLocation">true</bool>
+
     <!-- The duration (in milliseconds) that the radio will scan for a signal
          when there's no network connection. If the scan doesn't timeout, use zero -->
     <integer name="config_radioScanningTimeout">0</integer>
@@ -2283,4 +2298,8 @@
     <!-- The OEM specified sensor string type for the gesture to launch camera app, this value
          must match the value of config_cameraLaunchGestureSensorType in OEM's HAL -->
     <string translatable="false" name="config_cameraLaunchGestureSensorStringType"></string>
+
+    <!-- Whether to open UI submenus side by side with the top menu (as opposed to
+         replacing the top menu). -->
+    <bool name="config_enableCascadingSubmenus">false</bool>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index d2089cd..a2b6a7b 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2660,6 +2660,9 @@
        =============================================================== -->
     <eat-comment />
 
+    <public type="attr" name="listMenuViewStyle" />
+    <public type="attr" name="subMenuArrow" />
+
     <public type="style" name="Theme.Material.DayNight" />
     <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
     <public type="style" name="Theme.Material.DayNight.Dialog" />
@@ -2681,5 +2684,6 @@
     <public type="id" name="accessibilityActionSetProgress" />
     <public type="attr" name="activityWidth" />
     <public type="attr" name="activityHeight" />
+    <public type="attr" name="resizeableActivity" />
 
 </resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 2369c9b..5dc14e3 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -685,6 +685,10 @@
 
     <style name="Widget.Material.ListView.White"/>
 
+    <style name="Widget.Material.ListMenuView">
+        <item name="subMenuArrow">@drawable/ic_arrow_drop_right_black_24dp</item>
+    </style>
+
     <style name="Widget.Material.PopupWindow" parent="Widget.PopupWindow"/>
 
     <style name="Widget.Material.PopupWindow.ActionMode">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e04c743..48a7a1c5 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -158,6 +158,7 @@
   <java-symbol type="id" name="shortcut" />
   <java-symbol type="id" name="skip_button" />
   <java-symbol type="id" name="split_action_bar" />
+  <java-symbol type="id" name="submenuarrow" />
   <java-symbol type="id" name="submit_area" />
   <java-symbol type="id" name="switch_new" />
   <java-symbol type="id" name="switch_old" />
@@ -253,6 +254,10 @@
   <java-symbol type="bool" name="config_cellBroadcastAppLinks" />
   <java-symbol type="bool" name="config_duplicate_port_omadm_wappush" />
   <java-symbol type="bool" name="config_enableAutoPowerModes" />
+  <java-symbol type="integer" name="config_autoPowerModeThresholdAngle" />
+  <java-symbol type="integer" name="config_autoPowerModeAnyMotionSensor" />
+  <java-symbol type="bool" name="config_autoPowerModePreferWristTilt" />
+  <java-symbol type="bool" name="config_autoPowerModePrefetchLocation" />
   <java-symbol type="bool" name="config_enable_emergency_call_while_sim_locked" />
   <java-symbol type="bool" name="config_enable_puk_unlock_screen" />
   <java-symbol type="bool" name="config_enableBurnInProtection" />
@@ -2185,6 +2190,8 @@
   <java-symbol type="string" name="prohibit_manual_network_selection_in_gobal_mode" />
   <java-symbol type="id" name="profile_button" />
 
+  <java-symbol type="bool" name="config_enableCascadingSubmenus" />
+
   <!-- From SignalStrength -->
   <java-symbol type="integer" name="config_LTE_RSRP_threshold_type" />
 
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index e406ae0..3010190 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -238,6 +238,7 @@
         <item name="gridViewStyle">@style/Widget.Material.GridView</item>
         <item name="imageButtonStyle">@style/Widget.Material.ImageButton</item>
         <item name="imageWellStyle">@style/Widget.Material.ImageWell</item>
+        <item name="listMenuViewStyle">@style/Widget.Material.ListMenuView</item>
         <item name="listViewStyle">@style/Widget.Material.ListView</item>
         <item name="listViewWhiteStyle">@style/Widget.Material.ListView.White</item>
         <item name="popupWindowStyle">@style/Widget.Material.PopupWindow</item>
@@ -594,6 +595,7 @@
         <item name="gridViewStyle">@style/Widget.Material.Light.GridView</item>
         <item name="imageButtonStyle">@style/Widget.Material.Light.ImageButton</item>
         <item name="imageWellStyle">@style/Widget.Material.Light.ImageWell</item>
+        <item name="listMenuViewStyle">@style/Widget.Material.ListMenuView</item>
         <item name="listViewStyle">@style/Widget.Material.Light.ListView</item>
         <item name="listViewWhiteStyle">@style/Widget.Material.Light.ListView.White</item>
         <item name="popupWindowStyle">@style/Widget.Material.Light.PopupWindow</item>
diff --git a/core/tests/bluetoothtests/AndroidManifest.xml b/core/tests/bluetoothtests/AndroidManifest.xml
index e43ba12..7f9d874 100644
--- a/core/tests/bluetoothtests/AndroidManifest.xml
+++ b/core/tests/bluetoothtests/AndroidManifest.xml
@@ -21,6 +21,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
     <uses-permission android:name="android.permission.BROADCAST_STICKY" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS" />
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
diff --git a/core/tests/coretests/src/android/animation/AutoCancelTest.java b/core/tests/coretests/src/android/animation/AutoCancelTest.java
index b1f88db..5810818 100644
--- a/core/tests/coretests/src/android/animation/AutoCancelTest.java
+++ b/core/tests/coretests/src/android/animation/AutoCancelTest.java
@@ -18,10 +18,12 @@
 import android.os.Handler;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
 
 import java.util.HashMap;
 import java.util.concurrent.TimeUnit;
 
+@Suppress  // Failing
 public class AutoCancelTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
 
     boolean mAnimX1Canceled = false;
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
index d99ee80..6d20503 100644
--- a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -15,13 +15,21 @@
 */
 package android.animation;
 
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.SystemClock;
 import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.view.Choreographer;
+import android.view.animation.LinearInterpolator;
+
+import java.util.ArrayList;
 
 import static android.test.MoreAsserts.assertNotEqual;
 
 public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> {
+    private static final long WAIT_TIME_OUT = 5000;
     private ValueAnimator a1;
     private ValueAnimator a2;
 
@@ -34,6 +42,9 @@
     private final static int A2_START_VALUE = 100;
     private final static int A2_END_VALUE = 200;
 
+    private final static long DEFAULT_FRAME_INTERVAL = 5; //ms
+    private final static long COMMIT_DELAY = 3; //ms
+
     public ValueAnimatorTests() {
         super(BasicAnimatorActivity.class);
     }
@@ -47,9 +58,9 @@
 
     @Override
     public void tearDown() throws Exception {
-        super.tearDown();
         a1 = null;
         a2 = null;
+        super.tearDown();
     }
 
     @SmallTest
@@ -492,10 +503,265 @@
         });
     }
 
+    @SmallTest
+    public void testUpdateListener() throws InterruptedException {
+
+        final MyFrameCallbackProvider provider = new MyFrameCallbackProvider();
+        long sleep = 0;
+        while (provider.mHandler == null) {
+            Thread.sleep(POLL_INTERVAL);
+            sleep += POLL_INTERVAL;
+            if (sleep > WAIT_TIME_OUT) {
+                break;
+            }
+        }
+        // Either the looper has started, or timed out
+        assertNotNull(provider.mHandler);
+
+        final MyListener listener = new MyListener();
+        final MyUpdateListener l1 = new MyUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                long currentTime = SystemClock.uptimeMillis();
+                long frameDelay = provider.getFrameDelay();
+                if (lastUpdateTime > 0) {
+                    // Error tolerance here is one frame.
+                    assertTrue((currentTime - lastUpdateTime) < frameDelay * 2);
+                } else {
+                    // First frame:
+                    assertTrue(listener.startCalled);
+                    assertTrue(listener.startTime > 0);
+                    assertTrue(currentTime - listener.startTime < frameDelay * 2);
+                }
+                super.onAnimationUpdate(animation);
+            }
+        };
+        a1.addUpdateListener(l1);
+        a1.addListener(listener);
+        a1.setStartDelay(100);
+
+        provider.mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                AnimationHandler.getInstance().setProvider(provider);
+                a1.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        assertTrue(a1.isStarted());
+        Thread.sleep(a1.getTotalDuration() + TOLERANCE);
+        // Finished by now.
+        assertFalse(a1.isStarted());
+        assertTrue(listener.endTime > 0);
+
+        // Check the time difference between last frame and end time.
+        assertTrue(listener.endTime >= l1.lastUpdateTime);
+        assertTrue(listener.endTime - l1.lastUpdateTime < 2 * provider.getFrameDelay());
+    }
+
+
+    @SmallTest
+    public void testConcurrentModification() throws Throwable {
+        // Attempt to modify list of animations as the list is being iterated
+        final ValueAnimator a0 = ValueAnimator.ofInt(100, 200).setDuration(500);
+        final ValueAnimator a3 = ValueAnimator.ofFloat(0, 1).setDuration(500);
+        final ValueAnimator a4 = ValueAnimator.ofInt(200, 300).setDuration(500);
+        final MyListener listener = new MyListener() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                super.onAnimationEnd(anim);
+                // AnimationHandler should be iterating the list at the moment, end/cancel all
+                // the other animations. No ConcurrentModificationException should happen.
+                a0.cancel();
+                a1.end();
+                a3.end();
+                a4.cancel();
+            }
+        };
+        a2.addListener(listener);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a0.start();
+                a1.start();
+                a2.start();
+                a3.start();
+                a4.start();
+            }
+        });
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a0.isStarted());
+                assertTrue(a1.isStarted());
+                assertTrue(a2.isStarted());
+                assertTrue(a3.isStarted());
+                assertTrue(a4.isStarted());
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // End the animator that should be in the middle of the list.
+                a2.end();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        assertTrue(listener.endCalled);
+        assertFalse(a0.isStarted());
+        assertFalse(a1.isStarted());
+        assertFalse(a2.isStarted());
+        assertFalse(a3.isStarted());
+        assertFalse(a4.isStarted());
+    }
+
+    @SmallTest
+    public void testASeek() throws Throwable {
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        final MyUpdateListener updateListener1 = new MyUpdateListener();
+        final MyUpdateListener updateListener2 = new MyUpdateListener();
+        final float a1StartFraction = 0.2f;
+        final float a2StartFraction = 0.3f;
+
+        // Extend duration so we have plenty of latitude to manipulate the animations when they
+        // are running.
+        a1.setDuration(1000);
+        a2.setDuration(1000);
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a1.addUpdateListener(updateListener1);
+        a2.addUpdateListener(updateListener2);
+        TimeInterpolator interpolator = new LinearInterpolator();
+        a1.setInterpolator(interpolator);
+        a2.setInterpolator(interpolator);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+
+                // Test isRunning() and isStarted() before and after seek
+                a1.setCurrentFraction(a1StartFraction);
+                a2.setCurrentFraction(a2StartFraction);
+
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+
+        // Start animation and seek during the animation.
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+                assertEquals(a1StartFraction, a1.getAnimatedFraction());
+                assertEquals(a2StartFraction, a2.getAnimatedFraction());
+
+                a1.start();
+                a2.start();
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        final float halfwayFraction = 0.5f;
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+
+                // Check whether the animations start from the seeking fraction
+                assertTrue(updateListener1.startFraction >= a1StartFraction);
+                assertTrue(updateListener2.startFraction >= a2StartFraction);
+
+                assertTrue(a1.isStarted());
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isStarted());
+                assertTrue(a2.isRunning());
+
+                a1.setCurrentFraction(halfwayFraction);
+                a2.setCurrentFraction(halfwayFraction);
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+
+        // Check that seeking during running doesn't change animation's internal state
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.startCalled);
+                assertTrue(l2.startCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+
+                assertTrue(a1.isStarted());
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isStarted());
+                assertTrue(a2.isRunning());
+            }
+        });
+
+        // Wait until the animators finish successfully.
+        long wait = Math.max(a1.getTotalDuration(), a2.getTotalDuration());
+        Thread.sleep(wait);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Verify that the animators have finished.
+                assertTrue(l1.endCalled);
+                assertTrue(l2.endCalled);
+
+                assertFalse(a1.isStarted());
+                assertFalse(a2.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isRunning());
+            }
+        });
+
+        // Re-start animator a1 after it ends normally, and check that seek value from last run
+        // does not affect the new run.
+        updateListener1.reset();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(updateListener1.wasRunning);
+                assertTrue(updateListener1.startFraction >= 0);
+                assertTrue(updateListener1.startFraction < halfwayFraction);
+                a1.end();
+            }
+        });
+
+    }
+
     class MyUpdateListener implements ValueAnimator.AnimatorUpdateListener {
         boolean wasRunning = false;
         long firstRunningFrameTime = -1;
         long lastUpdateTime = -1;
+        float startFraction = 0;
 
         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
@@ -503,24 +769,36 @@
             if (animation.isRunning() && !wasRunning) {
                 // Delay has passed
                 firstRunningFrameTime = lastUpdateTime;
+                startFraction = animation.getAnimatedFraction();
                 wasRunning = animation.isRunning();
             }
         }
+
+        void reset() {
+            wasRunning = false;
+            firstRunningFrameTime = -1;
+            lastUpdateTime = -1;
+            startFraction = 0;
+        }
     }
 
     class MyListener implements Animator.AnimatorListener {
         boolean startCalled = false;
         boolean cancelCalled = false;
         boolean endCalled = false;
+        long startTime = -1;
+        long endTime = -1;
 
         @Override
         public void onAnimationStart(Animator animation) {
             startCalled = true;
+            startTime = SystemClock.uptimeMillis();
         }
 
         @Override
         public void onAnimationEnd(Animator animation) {
             endCalled = true;
+            endTime = SystemClock.uptimeMillis();
         }
 
         @Override
@@ -548,4 +826,72 @@
             resumeCalled = true;
         }
     }
+
+    class MyFrameCallbackProvider implements AnimationHandler.AnimationFrameCallbackProvider {
+
+        Handler mHandler = null;
+        private final static int MSG_FRAME = 0;
+        private long mFrameDelay = DEFAULT_FRAME_INTERVAL;
+        private ArrayList<Choreographer.FrameCallback> mFrameCallbacks = new ArrayList<>();
+
+        final LooperThread mThread = new LooperThread();
+
+        public MyFrameCallbackProvider() {
+            mThread.start();
+        }
+
+        @Override
+        public void postFrameCallback(Choreographer.FrameCallback callback) {
+            mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay);
+            if (!mFrameCallbacks.contains(callback)) {
+                mFrameCallbacks.add(callback);
+            }
+        }
+
+        @Override
+        public void postCommitCallback(Runnable runnable) {
+            // Run the runnable after a commit delay
+            mHandler.postDelayed(runnable, COMMIT_DELAY);
+        }
+
+        @Override
+        public long getFrameTime() {
+            return SystemClock.uptimeMillis();
+        }
+
+        @Override
+        public long getFrameDelay() {
+            return mFrameDelay;
+        }
+
+        @Override
+        public void setFrameDelay(long delay) {
+            mFrameDelay = delay;
+            if (mFrameCallbacks.size() != 0) {
+                mHandler.removeMessages(MSG_FRAME);
+                mHandler.sendEmptyMessageDelayed(MSG_FRAME, mFrameDelay);
+            }
+        }
+
+        class LooperThread extends Thread {
+            public void run() {
+                Looper.prepare();
+                mHandler = new Handler() {
+                    public void handleMessage(Message msg) {
+                        // Handle message here.
+                        switch (msg.what) {
+                            case MSG_FRAME:
+                                for (int i = 0; i < mFrameCallbacks.size(); i++) {
+                                    mFrameCallbacks.get(i).doFrame(SystemClock.uptimeMillis());
+                                }
+                                break;
+                            default:
+                                break;
+                        }
+                    }
+                };
+                Looper.loop();
+            }
+        }
+    }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index 2615a28..e6d3158 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -28,7 +28,6 @@
 import android.net.Uri;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.provider.Settings;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -37,7 +36,6 @@
 import java.util.List;
 
 /** Unit test for SettingsProvider. */
-@Suppress  // Failing.
 public class SettingsProviderTest extends AndroidTestCase {
     @MediumTest
     public void testNameValueCache() {
@@ -53,84 +51,108 @@
         assertEquals(1, r.delete(Settings.Secure.getUriFor("test_service"), null, null));
         assertEquals(null, Settings.Secure.getString(r, "test_service"));
 
-        // Try all the same things in the System table
-        Settings.System.putString(r, "test_setting", "Value");
-        assertEquals("Value", Settings.System.getString(r, "test_setting"));
-
-        Settings.System.putString(r, "test_setting", "New");
-        assertEquals("New", Settings.System.getString(r, "test_setting"));
-
-        assertEquals(1, r.delete(Settings.System.getUriFor("test_setting"), null, null));
-        assertEquals(null, Settings.System.getString(r, "test_setting"));
+        // Apps should not be able to use System settings.
+        try {
+            Settings.System.putString(r, "test_setting", "Value");
+            fail("IllegalArgumentException expected");
+        } catch (java.lang.IllegalArgumentException e) {
+            // expected
+        }
     }
 
     @MediumTest
-    public void testRowNameContentUri() {
+    public void testRowNameContentUriForSecure() {
+        final String testKey = "testRowNameContentUriForSecure";
+        final String testValue = "testValue";
+        final String secondTestValue = "testValueNew";
+
+        try {
+            testRowNameContentUri(Settings.Secure.CONTENT_URI, Settings.Secure.NAME,
+                    Settings.Secure.VALUE, testKey, testValue, secondTestValue);
+        } finally {
+            // clean up
+            Settings.Secure.putString(getContext().getContentResolver(), testKey, null);
+        }
+    }
+
+    @MediumTest
+    public void testRowNameContentUriForSystem() {
+        final String testKey = Settings.System.VIBRATE_ON;
+        assertTrue("Settings.System.PUBLIC_SETTINGS cannot be empty.  We need to use one of it"
+                + " for testing.  Only settings key in this collection will be accepted by the"
+                + " framework.", Settings.System.PUBLIC_SETTINGS.contains(testKey));
+        final String testValue = "0";
+        final String secondTestValue = "1";
+        final String oldValue =
+                Settings.System.getString(getContext().getContentResolver(), testKey);
+
+        try {
+            testRowNameContentUri(Settings.System.CONTENT_URI, Settings.System.NAME,
+                    Settings.System.VALUE, testKey, testValue, secondTestValue);
+        } finally {
+            // restore old value
+            if (oldValue != null) {
+                Settings.System.putString(getContext().getContentResolver(), testKey, oldValue);
+            }
+        }
+    }
+
+    private void testRowNameContentUri(Uri table, String nameField, String valueField,
+            String testKey, String testValue, String secondTestValue) {
         ContentResolver r = getContext().getContentResolver();
 
-        assertEquals("content://settings/system/test_setting",
-                Settings.System.getUriFor("test_setting").toString());
-        assertEquals("content://settings/secure/test_service",
-                Settings.Secure.getUriFor("test_service").toString());
+        ContentValues v = new ContentValues();
+        v.put(nameField, testKey);
+        v.put(valueField, testValue);
 
-        // These tables use the row name (not ID) as their content URI.
-        Uri tables[] = { Settings.System.CONTENT_URI, Settings.Secure.CONTENT_URI };
-        for (Uri table : tables) {
-            ContentValues v = new ContentValues();
-            v.put(Settings.System.NAME, "test_key");
-            v.put(Settings.System.VALUE, "Test");
-            Uri uri = r.insert(table, v);
-            assertEquals(table.toString() + "/test_key", uri.toString());
+        r.insert(table, v);
+        Uri uri = Uri.parse(table.toString() + "/" + testKey);
 
-            // Query with a specific URI and no WHERE clause succeeds.
-            Cursor c = r.query(uri, null, null, null, null);
-            try {
-                assertTrue(c.moveToNext());
-                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
-                assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
-                assertFalse(c.moveToNext());
-            } finally {
-                c.close();
-            }
-
-            // Query with a specific URI and a WHERE clause fails.
-            try {
-                r.query(uri, null, "1", null, null);
-                fail("UnsupportedOperationException expected");
-            } catch (UnsupportedOperationException e) {
-                if (!e.toString().contains("WHERE clause")) throw e;
-            }
-
-            // Query with a tablewide URI and a WHERE clause succeeds.
-            c = r.query(table, null, "name='test_key'", null, null);
-            try {
-                assertTrue(c.moveToNext());
-                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
-                assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
-                assertFalse(c.moveToNext());
-            } finally {
-                c.close();
-            }
-
-            v = new ContentValues();
-            v.put(Settings.System.VALUE, "Toast");
-            assertEquals(1, r.update(uri, v, null, null));
-
-            c = r.query(uri, null, null, null, null);
-            try {
-                assertTrue(c.moveToNext());
-                assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
-                assertEquals("Toast", c.getString(c.getColumnIndex(Settings.System.VALUE)));
-                assertFalse(c.moveToNext());
-            } finally {
-                c.close();
-            }
-
-            assertEquals(1, r.delete(uri, null, null));
+        // Query with a specific URI and no WHERE clause succeeds.
+        Cursor c = r.query(uri, null, null, null, null);
+        try {
+            assertTrue(c.moveToNext());
+            assertEquals(testKey, c.getString(c.getColumnIndex(nameField)));
+            assertEquals(testValue, c.getString(c.getColumnIndex(valueField)));
+            assertFalse(c.moveToNext());
+        } finally {
+            c.close();
         }
 
-        assertEquals(null, Settings.System.getString(r, "test_key"));
-        assertEquals(null, Settings.Secure.getString(r, "test_key"));
+        // Query with a specific URI and a WHERE clause fails.
+        try {
+            r.query(uri, null, "1", null, null);
+            fail("IllegalArgumentException expected");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        // Query with a tablewide URI and a WHERE clause succeeds.
+        c = r.query(table, null, "name='" + testKey + "'", null, null);
+        try {
+            assertTrue(c.moveToNext());
+            assertEquals(testKey, c.getString(c.getColumnIndex(nameField)));
+            assertEquals(testValue, c.getString(c.getColumnIndex(valueField)));
+            assertFalse(c.moveToNext());
+        } finally {
+            c.close();
+        }
+
+        v = new ContentValues();
+        // NAME is still needed, although the uri should be specific enough. Why?
+        v.put(nameField, testKey);
+        v.put(valueField, secondTestValue);
+        assertEquals(1, r.update(uri, v, null, null));
+
+        c = r.query(uri, null, null, null, null);
+        try {
+            assertTrue(c.moveToNext());
+            assertEquals(testKey, c.getString(c.getColumnIndex(nameField)));
+            assertEquals(secondTestValue, c.getString(c.getColumnIndex(valueField)));
+            assertFalse(c.moveToNext());
+        } finally {
+            c.close();
+        }
     }
 
     @MediumTest
@@ -139,7 +161,7 @@
         ContentResolver r = getContext().getContentResolver();
 
         // Make sure there's an owner
-        assertTrue(findUser(um, UserHandle.USER_OWNER));
+        assertTrue(findUser(um, UserHandle.USER_SYSTEM));
 
         // create a new user to use for testing
         UserInfo otherUser = um.createUser("TestUser1", UserInfo.FLAG_GUEST);
@@ -148,21 +170,17 @@
             assertNotSame("Current calling user id should not be the new guest user",
                     otherUser.id, UserHandle.getCallingUserId());
 
-            Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "gps");
-            Settings.Secure.putStringForUser(r,
-                    Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "network", otherUser.id);
+            final String testKey = "testSettingsChangeForOtherUser";
+            final String testValue1 = "value1";
+            final String testValue2 = "value2";
+            Settings.Secure.putString(r, testKey, testValue1);
+            Settings.Secure.putStringForUser(r, testKey, testValue2, otherUser.id);
 
-            assertEquals("gps",
-                    Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
-            assertEquals("network", Settings.Secure.getStringForUser(
-                    r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, otherUser.id));
+            assertEquals(testValue1, Settings.Secure.getString(r, testKey));
+            assertEquals(testValue2, Settings.Secure.getStringForUser(r, testKey, otherUser.id));
 
             assertNotSame("Current calling user id should not be the new guest user",
                     otherUser.id, UserHandle.getCallingUserId());
-            Settings.Secure.setLocationProviderEnabledForUser(r, "network", false, otherUser.id);
-            assertEquals("", Settings.Secure.getStringForUser(
-                    r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, otherUser.id));
-
         } finally {
             // Tidy up
             um.removeUser(otherUser.id);
@@ -170,6 +188,7 @@
     }
 
     @MediumTest
+    @Suppress  // Settings.Bookmarks uses a query format that's not supported now.
     public void testRowNumberContentUri() {
         ContentResolver r = getContext().getContentResolver();
 
@@ -196,47 +215,56 @@
     public void testParseProviderList() {
         ContentResolver r = getContext().getContentResolver();
 
-        // Make sure we get out what we put in.
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "test1,test2,test3");
-        assertEquals(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED),
-                "test1,test2,test3");
-
+        // We only accept "+value" and "-value"
         // Test adding a value
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "");
         Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test1");
-        assertEquals("test1",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test1"));
 
         // Test adding a second value
         Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test2");
-        assertEquals("test1,test2",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test1"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test2"));
 
         // Test adding a third value
         Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test3");
-        assertEquals("test1,test2,test3",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test1"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test2"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test3"));
 
         // Test deleting the first value in a 3 item list
         Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test1");
-        assertEquals("test2,test3",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test1"));
 
         // Test deleting the middle value in a 3 item list
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "test1,test2,test3");
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test2");
-        assertEquals("test1,test3",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test4");
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test2"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test3"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test4"));
+        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test3");
+        assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test3"));
 
         // Test deleting the last value in a 3 item list
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED,
-                "test1,test2,test3");
-        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test3");
-        assertEquals("test1,test2",
-                Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED));
+        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "+test5");
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test2"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test4"));
+        assertTrue(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test5"));
+        Settings.Secure.putString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "-test5");
+        assertFalse(Settings.Secure.getString(r, Settings.Secure.LOCATION_PROVIDERS_ALLOWED)
+                .contains("test5"));
      }
 
     private boolean findUser(UserManager um, int userHandle) {
@@ -254,7 +282,7 @@
         ContentResolver r = getContext().getContentResolver();
 
         // Make sure there's an owner
-        assertTrue(findUser(um, UserHandle.USER_OWNER));
+        assertTrue(findUser(um, UserHandle.USER_SYSTEM));
 
         // create a new user to use for testing
         UserInfo user = um.createUser("TestUser1", UserInfo.FLAG_GUEST);
@@ -266,12 +294,12 @@
             final int SELF_VALUE = 40;
             final int OTHER_VALUE = 27;
 
-            Settings.System.putInt(r, TEST_KEY, SELF_VALUE);
-            Settings.System.putIntForUser(r, TEST_KEY, OTHER_VALUE, user.id);
+            Settings.Secure.putInt(r, TEST_KEY, SELF_VALUE);
+            Settings.Secure.putIntForUser(r, TEST_KEY, OTHER_VALUE, user.id);
 
             // Verify that they read back as intended
-            int myValue = Settings.System.getInt(r, TEST_KEY, 0);
-            int otherValue = Settings.System.getIntForUser(r, TEST_KEY, 0, user.id);
+            int myValue = Settings.Secure.getInt(r, TEST_KEY, 0);
+            int otherValue = Settings.Secure.getIntForUser(r, TEST_KEY, 0, user.id);
             assertTrue("Running as user " + UserHandle.myUserId()
                     + " and reading/writing as user " + user.id
                     + ", expected to read " + SELF_VALUE + " but got " + myValue,
@@ -310,7 +338,8 @@
         assertCanBeHandled(new Intent(Settings.ACTION_MEMORY_CARD_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_NETWORK_OPERATOR_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_PRIVACY_SETTINGS));
-        assertCanBeHandled(new Intent(Settings.ACTION_QUICK_LAUNCH_SETTINGS));
+        //TODO: seems no one is using this anymore.
+//        assertCanBeHandled(new Intent(Settings.ACTION_QUICK_LAUNCH_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_SEARCH_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_SECURITY_SETTINGS));
         assertCanBeHandled(new Intent(Settings.ACTION_SETTINGS));
diff --git a/core/tests/coretests/src/android/view/HandlerActionQueueTest.java b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
new file mode 100644
index 0000000..fd8f23a
--- /dev/null
+++ b/core/tests/coretests/src/android/view/HandlerActionQueueTest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerActionQueueTest extends AndroidTestCase {
+
+    @SmallTest
+    public void testPostAndRemove() {
+        HandlerActionQueue runQueue = new HandlerActionQueue();
+        MockRunnable runnable1 = new MockRunnable();
+        MockRunnable runnable2 = new MockRunnable();
+        MockRunnable runnable3 = new MockRunnable();
+
+        runQueue.post(runnable1);
+        runQueue.post(runnable1);
+        runQueue.post(runnable2);
+        runQueue.postDelayed(runnable1, 100);
+        runQueue.postDelayed(null, 500);
+        assertEquals(5, runQueue.size());
+        assertEquals(0, runQueue.getDelay(0));
+        assertEquals(0, runQueue.getDelay(1));
+        assertEquals(0, runQueue.getDelay(2));
+        assertEquals(100, runQueue.getDelay(3));
+        assertEquals(500, runQueue.getDelay(4));
+        assertEquals(500, runQueue.getDelay(4));
+        assertEquals(runnable1, runQueue.getRunnable(0));
+        assertEquals(runnable1, runQueue.getRunnable(1));
+        assertEquals(runnable2, runQueue.getRunnable(2));
+        assertEquals(runnable1, runQueue.getRunnable(3));
+        assertEquals(null, runQueue.getRunnable(4));
+
+        runQueue.removeCallbacks(runnable1);
+        assertEquals(2, runQueue.size());
+        assertEquals(0, runQueue.getDelay(0));
+        assertEquals(500, runQueue.getDelay(1));
+        assertEquals(runnable2, runQueue.getRunnable(0));
+        assertEquals(null, runQueue.getRunnable(1));
+
+        try {
+            assertNull(runQueue.getRunnable(2));
+            assertFalse(true);
+        } catch (IndexOutOfBoundsException e) {
+            // Should throw an exception.
+        }
+
+        runQueue.removeCallbacks(runnable3);
+        assertEquals(2, runQueue.size());
+
+        runQueue.removeCallbacks(runnable2);
+        assertEquals(1, runQueue.size());
+        assertEquals(null, runQueue.getRunnable(0));
+
+        runQueue.removeCallbacks(null);
+        assertEquals(0, runQueue.size());
+    }
+
+    private static class MockRunnable implements Runnable {
+        @Override
+        public void run() {
+
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
index 7938cba..bc3776c 100644
--- a/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
+++ b/core/tests/coretests/src/android/widget/listview/ListManagedCursorTest.java
@@ -17,8 +17,7 @@
 package android.widget.listview;
 
 import android.app.Instrumentation;
-import android.test.ActivityInstrumentationTestCase;
-import android.test.FlakyTest;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.MediumTest;
 import android.view.KeyEvent;
@@ -28,12 +27,12 @@
 /**
  * Tests restoring the scroll position in a list with a managed cursor.
  */
-public class ListManagedCursorTest extends ActivityInstrumentationTestCase<ListManagedCursor> {
+public class ListManagedCursorTest extends ActivityInstrumentationTestCase2<ListManagedCursor> {
     private ListManagedCursor mActivity;
     private ListView mListView;
 
     public ListManagedCursorTest() {
-        super("com.android.frameworks.coretests", ListManagedCursor.class);
+        super(ListManagedCursor.class);
     }
 
     @Override
@@ -48,86 +47,46 @@
     public void testPreconditions() {
         assertNotNull(mActivity);
         assertNotNull(mListView);
-        
+
         assertEquals(0, mListView.getFirstVisiblePosition());
     }
-    
+
     /**
      * Scroll the list using arrows, launch new activity, hit back, make sure we're still scrolled.
      */
     @LargeTest
     public void testKeyScrolling() {
         Instrumentation inst = getInstrumentation();
-        
+
         int firstVisiblePosition = arrowScroll(inst);
-        
+
         inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
         inst.waitForIdleSync();
-        
-        assertTrue("List changed to touch mode", !mListView.isInTouchMode()); 
-        assertTrue("List did not preserve scroll position", 
-                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
+
+        assertTrue("List changed to touch mode", !mListView.isInTouchMode());
+        assertTrue("List did not preserve scroll position",
+                firstVisiblePosition == mListView.getFirstVisiblePosition());
     }
 
     /**
-     * Scroll the list using touch, launch new activity, hit back, make sure we're still scrolled.
-     */
-    @LargeTest
-    public void testTouchScrolling() {
-        Instrumentation inst = getInstrumentation();
-        
-       int firstVisiblePosition = touchScroll(inst);
-        
-        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
-        inst.waitForIdleSync();
-        
-        assertTrue("List not in touch mode", mListView.isInTouchMode()); 
-        assertTrue("List did not preserve scroll position", 
-                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
-    }
-    
-    /**
      * Scroll the list using arrows, launch new activity, change to touch mode, hit back, make sure
      * we're still scrolled.
      */
     @LargeTest
     public void testKeyScrollingToTouchMode() {
         Instrumentation inst = getInstrumentation();
-        
+
         int firstVisiblePosition = arrowScroll(inst);
-        
-        TouchUtils.dragQuarterScreenUp(this);
+
+        TouchUtils.dragQuarterScreenUp(this, getActivity());
         inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
         inst.waitForIdleSync();
-        
-        assertTrue("List did not change to touch mode", mListView.isInTouchMode()); 
-        assertTrue("List did not preserve scroll position", 
-                firstVisiblePosition == mListView.getFirstVisiblePosition()); 
+
+        assertTrue("List did not change to touch mode", mListView.isInTouchMode());
+        assertTrue("List did not preserve scroll position",
+                firstVisiblePosition == mListView.getFirstVisiblePosition());
     }
 
-
-    /**
-     * Scroll the list using touch, launch new activity, change to trackball mode, hit back, make
-     * sure we're still scrolled.
-     */
-    @FlakyTest(tolerance=3)
-    @LargeTest
-    public void testTouchScrollingToTrackballMode() {
-        Instrumentation inst = getInstrumentation();
-
-        int firstVisiblePosition = touchScroll(inst);
-
-        inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        inst.waitForIdleSync();
-        inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
-        inst.waitForIdleSync();
-        inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
-        inst.waitForIdleSync();
-        assertTrue("List not in trackball mode", !mListView.isInTouchMode());
-        assertTrue("List did not preserve scroll position", firstVisiblePosition == mListView
-                .getFirstVisiblePosition());
-    }
-    
     public int arrowScroll(Instrumentation inst) {
         int count = mListView.getChildCount();
 
@@ -151,30 +110,4 @@
 
         return firstVisiblePosition;
     }
-
-    public int touchScroll(Instrumentation inst) {
-        TouchUtils.dragQuarterScreenUp(this);
-        inst.waitForIdleSync();
-        TouchUtils.dragQuarterScreenUp(this);
-        inst.waitForIdleSync();
-        TouchUtils.dragQuarterScreenUp(this);
-        inst.waitForIdleSync();
-        TouchUtils.dragQuarterScreenUp(this);
-        inst.waitForIdleSync();
-
-        int firstVisiblePosition = mListView.getFirstVisiblePosition();
-        assertTrue("Touch scroll did not happen", firstVisiblePosition > 0);
-        assertTrue("List not in touch mode", mListView.isInTouchMode());
-
-        TouchUtils.clickView(this, mListView.getChildAt(mListView.getChildCount() - 1));
-        inst.waitForIdleSync();
-
-        try {
-            Thread.sleep(3000);
-        } catch (InterruptedException e) {
-            e.printStackTrace();
-        }
-
-        return firstVisiblePosition;
-    }
 }
diff --git a/docs/html-intl/intl/es/index.jd b/docs/html-intl/intl/es/index.jd
index e23c99f..4065439 100644
--- a/docs/html-intl/intl/es/index.jd
+++ b/docs/html-intl/intl/es/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">Prepárese para la próxima versión de
 Android. Pruebe sus aplicaciones en Nexus 5, 6, 9 y Player. </p>
 
@@ -31,7 +28,7 @@
           ¡Empiece hoy mismo!</a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
         </a>
       </div>
     </div>
diff --git a/docs/html-intl/intl/es/preview/download.jd b/docs/html-intl/intl/es/preview/download.jd
index d71d8fd..d77242c 100644
--- a/docs/html-intl/intl/es/preview/download.jd
+++ b/docs/html-intl/intl/es/preview/download.jd
@@ -164,14 +164,16 @@
   <div id="qv">
     <h2>Contenido del documento</h2>
       <ol>
-        <li><a href="#sdk">SDK de la versión preliminar</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">Documentación para desarrolladores</a></li>
         <li><a href="#images">Imágenes del sistema de hardware</a></li>
       </ol>
 
       <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+		   <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
+
         </ol>
   </div>
 </div>
@@ -184,7 +186,7 @@
 </p>
 
 
-<h2 id="sdk">SDK de la versión preliminar</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   El SDK de la versión preliminar se encuentra disponible para descargarlo a través del <a href="{@docRoot}tools/help/sdk-manager.html">Administrador de SDK de Android</a>. Para obtener más información sobre cómo descargar y configurar el SDK de la versión preliminar, consulte la sección <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Configurar el SDK de la versión preliminar</a>.
@@ -204,11 +206,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -241,34 +243,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/es/preview/download_mp2.jd b/docs/html-intl/intl/es/preview/download_mp2.jd
new file mode 100644
index 0000000..d71d8fd
--- /dev/null
+++ b/docs/html-intl/intl/es/preview/download_mp2.jd
@@ -0,0 +1,360 @@
+page.title=Descargas
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">Antes de descargar e instalar los componentes del SDK de la versión preliminar de Android, debe aceptar los términos y las condiciones que se describen a continuación.
+</p>
+
+    <h2 class="norule">Términos y condiciones</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+Este es el Contrato de licencia de la versión preliminar del SDK de Android (el “Contrato de licencia”). 1.
+
+ Introducción 1.1 Se le otorga la licencia de la versión preliminar del SDK de Android (denominada “Versión preliminar” en este Contrato de licencia y que incluye específicamente los archivos de sistema de Android, las API agrupadas y los archivos de biblioteca de la Versión preliminar, si se encuentran disponibles), sujeto a los términos del Contrato de licencia.
+
+ El Contrato de licencia establece una relación legal vinculante entre usted y Google en relación con el uso que usted realice de la Versión preliminar. 1.2 “Android” hace referencia al conjunto de soluciones Android para dispositivos, según se encuentre disponible en el Proyecto de código abierto de Android (Android Open Source Project), que se encuentra en la siguiente URL: http://source.android.com/, y según se actualiza periódicamente. 1.3 “Google” hace referencia a Google Inc., una corporación de Delaware, con sede principal en 1600 Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos. 2.
+
+
+
+
+
+ Aceptación del Contrato de licencia 2.1 Para poder utilizar la Versión preliminar, primero debe aceptar el Contrato de licencia.
+
+ Si no acepta el Contrato de licencia, no podrá utilizar la Versión preliminar. 2.2 Al hacer clic para aceptar o utilizar la Versión preliminar, por medio del presente, usted acepta los términos del Contrato de licencia. 2.3 Usted no puede utilizar la Versión preliminar ni aceptar el Contrato de licencia si tiene prohibido recibir la Versión preliminar en virtud de las leyes de los Estados Unidos o de otros países, lo que incluye el país donde es residente o desde el que utilizará la Versión preliminar. 2.4 Si usted utilizará la Versión preliminar de forma interna, dentro de su compañía u organización, usted acepta quedar sujeto al Contrato de licencia en representación de su empleador u otra entidad, y expresa y garantiza que tiene plena autoridad legal para vincular a su empleador o a dicha entidad al Contrato de licencia.
+
+
+
+
+
+ Si no posee la autoridad exigida, no podrá aceptar el Contrato de licencia ni usar la Versión preliminar en representación de su empleador u otra entidad. 3.
+
+ Licencia de la Versión preliminar de Google 3.1 Sujeto a los términos del Contrato de licencia, Google le otorga una licencia libre de regalías, no asignable, no exclusiva, no transferible a terceros, limitada y revocable para utilizar la Versión preliminar, de forma personal o interna dentro de su compañía u organización, únicamente para desarrollar aplicaciones para ejecutar en la plataforma de Android. 3.2 Usted acepta que Google u otros terceros poseen todos los derechos legales, títulos e intereses en relación con la Versión preliminar, incluidos los Derechos de propiedad intelectual que existan en la Versión preliminar.
+
+
+
+ Los “Derechos de propiedad intelectual” hacen referencia a todos y cada uno de los derechos en virtud de las leyes de patentes, derechos de autor, secreto comercial y marca comercial, y todos los demás derechos de propiedad. Google se reserva todos los derechos que no se le otorguen expresamente. 3.3 No podrá utilizar la Versión preliminar para ningún otro propósito que no esté expresamente permitido en el Contrato de licencia.
+
+ Excepto en la medida que lo exijan las licencias correspondientes de terceros, no podrá: (a) copiar (excepto con fines de copia de seguridad), modificar, adaptar, redistribuir, descompilar, utilizar técnicas de ingeniería inversa, desarmar ni crear trabajos derivados de la Versión preliminar ni de ninguna de sus partes; ni (b) cargar ninguna parte de la Versión preliminar en un teléfono móvil ni en ningún otro dispositivo de hardware (a excepción de una computadora personal), ni podrá combinar ninguna parte de la Versión preliminar con otro software, ni distribuir algún software o dispositivo que incorpore alguna parte de la Versión preliminar. 3.4 Usted acepta que no tomará medidas que pudieran provocar la fragmentación de Android, incluidas, entre otras, la distribución y la participación en la creación o la promoción de un kit de desarrollo de software derivado de la Versión preliminar. 3.5 El uso, la reproducción y la distribución de los componentes de la Versión preliminar con licencia de software de código abierto están regidos exclusivamente por los términos de la licencia de ese software de código abierto y no de este Contrato de licencia.
+
+
+
+ Usted acepta mantener la licencia en buenas condiciones con respecto a dichas licencias de software de código abierto en virtud de todos los derechos otorgados y acepta abstenerse de realizar alguna acción que pueda poner fin, suspender o violar dichos derechos. 3.6 Usted acepta que la forma y la naturaleza de la Versión preliminar que proporciona Google pueden cambiar sin brindarle aviso previo y que las versiones futuras de la Versión preliminar pueden ser incompatibles con las aplicaciones desarrolladas en versiones anteriores de la Versión preliminar.
+
+ Usted acepta que Google puede (de forma permanente o temporal) dejar de proporcionarles la Versión preliminar (o cualquiera de las características incluidas en ella) a usted o a los usuarios, generalmente, a criterio exclusivo de Google, sin brindarle aviso previo. 3.7 Ninguna declaración de este Contrato de licencia le otorga el derecho de utilizar alguno de los nombres comerciales, las marcas comerciales, las marcas de servicio, los logotipos, los nombres de dominio ni otras características distintivas de marca de Google. 3.8 Usted acepta que no eliminará, ocultará ni alterará ninguno de los avisos de derechos de propiedad (lo que incluye los avisos de marca comercial y derechos de autor) que pudieran estar anexados o incluidos en la Versión preliminar. 4.
+
+
+
+
+
+ Uso que usted realiza de la Versión preliminar 4.1 Google acepta que ninguna declaración del Contrato de licencia le concede a Google derecho, título o interés alguno de su parte (o de parte de sus licenciantes), en virtud del Contrato de licencia, con respecto a las aplicaciones de software que usted desarrolle mediante el uso de la Versión preliminar, lo que incluye los derechos de propiedad intelectual que conlleven esas aplicaciones. 4.2 Usted acepta utilizar la Versión preliminar y escribir aplicaciones únicamente conforme a lo que permite (a) este Contrato de licencia y (b) las leyes, regulaciones, o prácticas y pautas generalmente aceptadas pertinentes en las jurisdicciones relevantes (lo que incluye las leyes sobre la exportación de datos o software hacia los Estados Unidos u otros países relevantes y desde ellos). 4.3 Usted acepta que si utiliza la Versión preliminar para desarrollar aplicaciones, protegerá la privacidad y los derechos legales de los usuarios.
+
+
+
+
+
+ Si los usuarios le proporcionan sus nombres de usuario, contraseñas u otra información de inicio de sesión o información personal, debe comunicarles a los usuarios que la información se encontrará disponible para su aplicación, y debe proporcionarles a dichos usuarios un aviso de privacidad con protección y validez legal. Si su aplicación almacena información personal o confidencial proporcionada por los usuarios, lo debe hacer de forma segura. Si los usuarios le proporcionan información sobre la cuenta de Google, su aplicación solo puede usar esa información para acceder a la cuenta de Google del usuario siempre que este le haya otorgado permiso para hacerlo y con los fines para los que se lo haya otorgado. 4.4 Usted acepta que no participará en ninguna actividad con la Versión preliminar (lo que incluye el desarrollo o la distribución de una aplicación) que interfiera, interrumpa, dañe o acceda sin autorización a servidores, redes u otras propiedades o servicios de Google o de algún tercero. 4.5 Usted acepta que es el único responsable (y que Google no asume responsabilidades hacia usted ni terceros) de los datos, el contenido o los recursos que usted cree, transmita o muestre a través de Android o las aplicaciones para Android, y de las consecuencias de sus acciones (lo que incluye la pérdida o el daño que Google pudiera sufrir) al hacerlo. 4.6 Usted acepta que es el único responsable (y que Google no asume responsabilidades hacia usted ni terceros) de cualquier incumplimiento de sus obligaciones en virtud de este Contrato de licencia, los contratos aplicables de terceros o los términos del servicio, o cualquier ley o regulación pertinentes, y de las consecuencias (lo que incluye las pérdidas o los daños que pudieran sufrir Google o algún tercero) de dichos incumplimientos. 4.7 La Versión preliminar se encuentra en desarrollo, y sus pruebas y comentarios son una parte importante del proceso de desarrollo.
+
+
+
+
+
+
+
+ Al utilizar la Versión preliminar, usted reconoce que la implementación de algunas características aún se encuentra en desarrollo y que no debe confiar en que la Versión preliminar contará con todas las funcionalidades de una versión estable. Usted acepta no distribuir públicamente ni enviar ninguna aplicación que utilice esta Versión preliminar, ya que esta Versión preliminar ya no se admitirá tras el lanzamiento del SDK oficial de Android. 5.
+
+ Sus credenciales de desarrollador 5.1 Usted acepta que es responsable de mantener la confidencialidad de toda credencial de desarrollador que Google pudiera otorgarle o que usted pudiera escoger, y que será el único responsable de todas las aplicaciones que se desarrollen con sus credenciales de desarrollador. 6.
+
+
+
+ Privacidad e información 6.1 A fin de poder innovar y mejorar de forma continua la Versión preliminar, Google podría recopilar ciertas estadísticas de uso del software, lo que incluye, entre otras características, un identificador único, la dirección IP asociada, el número de versión del software e información sobre las herramientas o los servicios de la Versión preliminar que se estén utilizando y la manera en que se estén utilizando.
+
+ Antes de que se recopile esta información, la Versión preliminar se lo notificará y le solicitará su permiso. Si no otorga su permiso, no se recopilará la información. 6.2 Los datos recopilados se analizan en el agregado para mejorar la Versión preliminar y se conservan de acuerdo con la política de privacidad de Google que se encuentra en el sitio http://www.google.com/policies/privacy/. 7.
+
+
+
+ Aplicaciones de terceros 7.1 Si utiliza la Versión preliminar para ejecutar aplicaciones desarrolladas por un tercero o que accedan a datos, contenido o recursos proporcionados por un tercero, usted acepta que Google no es responsable de esas aplicaciones, datos, contenido ni recursos.
+
+ Usted comprende que todos los datos, contenidos o recursos a los que podría acceder a través de esas aplicaciones de terceros son exclusiva responsabilidad de la persona que los origina y que Google no es responsable de las pérdidas ni los daños que usted pudiera experimentar como consecuencia del uso o acceso de cualquiera de esas aplicaciones, datos, contenido o recursos de terceros. 7.2 Usted debe saber que los datos, el contenido y los recursos que se le presentan a través de esa aplicación de un tercero pueden estar protegidos por derechos de propiedad intelectual que les pertenecen a sus proveedores (o a otras personas o compañías en representación de estos).
+
+ No puede modificar, alquilar, arrendar, prestar, vender, distribuir ni crear obras derivadas basadas en esos datos, contenidos o recursos (en su totalidad o en parte), a menos que los propietarios pertinentes le hayan otorgado permiso específicamente para hacerlo. 7.3 Usted acepta que el uso que haga de las aplicaciones, los datos, el contenido o los recursos de ese tercero puede estar sujeto a términos independientes entre usted y el tercero correspondiente. 8.
+
+
+
+ Uso de las API de Google 8.1 API de Google 8.1.1 Si utiliza alguna API para recuperar datos de Google, usted acepta que los datos pueden estar protegidos por derechos de propiedad intelectual que le pertenecen a Google o a las partes que proporcionan esos datos (o a otras personas o empresas en representación de estos).
+
+
+
+ El uso que realice de cualquiera de esas API puede estar sujeto a términos de servicio adicionales. No puede modificar, alquilar, arrendar, prestar, vender, distribuir ni crear obras derivadas basadas en esos datos (en su totalidad o en parte), a menos que los términos de servicio correspondientes lo permitan. 8.1.2 Si utiliza alguna API para recuperar datos de un usuario de Google, usted acepta y acuerda que solo podrá recuperar datos con el consentimiento explícito del usuario y solo con los fines limitados para los que el usuario le haya otorgado permiso para hacerlo. 9.
+
+
+
+ Finalización del Contrato de licencia 9.1 Este Contrato de licencia tendrá vigencia hasta que lo revoquen usted o Google, como se indica a continuación. 9.2 Si desea rescindir el Contrato de licencia, puede hacerlo al interrumpir el uso que realiza de la Versión preliminar y de las credenciales de desarrollador pertinentes. 9.3 Google puede, en cualquier momento, rescindir el Contrato de licencia, con causa o sin ella, después de notificárselo a usted. 9.4 El Contrato de licencia finalizará automáticamente, sin previo aviso ni acción alguna, tras la primera de las siguientes situaciones: (A) cuando Google deje de proporcionar la Versión preliminar o ciertas partes de esta a los usuarios en el país donde usted reside o desde el que utiliza el servicio; y (B) cuando Google emita una versión final del SDK de Android. 9.5 Si el Contrato de licencia se rescinde, se revocará la licencia que usted recibió en virtud de dicho contrato; usted deberá suspender inmediatamente todo uso de la Versión preliminar y las disposiciones de los párrafos 10, 11, 12 y 14 seguirán vigentes indefinidamente. 10.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ EXENCIONES DE RESPONSABILIDAD 10.1 USTED COMPRENDE Y ACEPTA EXPRESAMENTE QUE EL USO QUE REALICE DE LA VERSIÓN PRELIMINAR ES BAJO SU PROPIO RIESGO Y QUE LA VERSIÓN PRELIMINAR SE PROPORCIONA “EN LAS CONDICIONES EN LAS QUE SE ENCUENTRA” Y “SUJETA A DISPONIBILIDAD” SIN GARANTÍAS DE NINGÚN TIPO POR PARTE DE GOOGLE. 10.2 EL USO QUE USTED REALICE DE LA VERSIÓN PRELIMINAR Y DE TODO MATERIAL DESCARGADO U OBTENIDO DE ALGUNA OTRA MANERA MEDIANTE EL USO DE LA VERSIÓN PRELIMINAR ES A SU ENTERO RIESGO Y DISCRECIÓN, Y USTED ES EL ÚNICO RESPONSABLE DE CUALQUIER DAÑO QUE PUDIERA SUFRIR SU SISTEMA INFORMÁTICO U OTRO DISPOSITIVO, O DE LA PÉRDIDA DE DATOS COMO CONSECUENCIA DE DICHO USO.
+
+
+
+ SIN PERJUICIO DE LO MENCIONADO ANTERIORMENTE, USTED COMPRENDE QUE LA VERSIÓN PRELIMINAR NO ES UNA VERSIÓN ESTABLE, Y PUEDE CONTENER ERRORES, DEFECTOS Y VULNERABILIDADES DE SEGURIDAD QUE PUEDEN PROVOCAR DAÑOS SIGNIFICATIVOS, LO QUE INCLUYE LA PÉRDIDA COMPLETA E IRRECUPERABLE DEL USO DE SU SISTEMA INFORMÁTICO U OTRO DISPOSITIVO. 10.3 GOOGLE TAMBIÉN RECHAZA TODAS LAS GARANTÍAS Y CONDICIONES DE CUALQUIER TIPO, EXPRESAS O IMPLÍCITAS, INCLUIDAS, ENTRE OTRAS, LAS GARANTÍAS Y CONDICIONES DE COMERCIABILIDAD, IDONEIDAD PARA UN FIN DETERMINADO Y NO VIOLACIÓN. 11.
+
+
+
+ LIMITACIÓN DE RESPONSABILIDADES 11.1 USTED COMPRENDE Y ACEPTA EXPRESAMENTE QUE GOOGLE, SUS SUBSIDIARIAS Y FILIALES, Y SUS LICENCIANTES NO SERÁN RESPONSABLES ANTE USTED, EN VIRTUD DE NINGUNA TEORÍA DE RESPONSABILIDAD, POR NINGÚN DAÑO DIRECTO, INDIRECTO, INCIDENTAL, ESPECIAL, RESULTANTE NI PUNITIVO EN EL QUE PODRÍA HABER INCURRIDO, LO QUE INCLUYE LA PÉRDIDA DE DATOS, YA SEA QUE SE LE HAYA NOTIFICADO O NO A GOOGLE O A SUS REPRESENTANTES, O SOBRE CUYA POSIBILIDAD ESTOS DEBERÍAN HABER SABIDO. 12.
+
+
+
+ Indemnización 12.1 Hasta el grado máximo que permita la ley, usted acepta defender, indemnizar y eximir de responsabilidades a Google, sus filiales y sus respectivos directores, funcionarios, empleados y agentes, de todo tipo de reclamo, acción legal y proceso judicial, así como de las pérdidas, responsabilidades, daños, costos y gastos (incluidos los honorarios razonables de abogados) que surjan o se acumulen (a) del uso que usted realiza de la Versión preliminar, (b) de cualquier aplicación que desarrolle en la Versión preliminar que infrinja algún derecho de propiedad intelectual de cualquier persona, o que difame a cualquier persona o viole sus derechos de publicidad o privacidad, y (c) del incumplimiento por su parte del Contrato de licencia. 13.
+
+
+
+ Cambios en el Contrato de licencia 13.1 Google puede realizar cambios en el Contrato de licencia a medida que distribuye nuevas versiones de la Versión preliminar.
+
+ Cuando se realicen esos cambios, Google emitirá una nueva versión del Contrato de licencia, que estará disponible en el sitio web donde se ponga a la venta la Versión preliminar. 14.
+
+ Términos legales generales 14.1 El Contrato de licencia constituye el contrato legal integral entre usted y Google, y rige el uso que usted realice de la Versión preliminar (a excepción de los servicios que Google pueda proporcionarle en virtud de un contrato por escrito independiente), y reemplaza totalmente cualquier contrato anterior entre usted y Google en relación con la Versión preliminar. 14.2 Usted acepta que, si Google no ejerce ni impone un derecho o recurso legal especificados en el Contrato de licencia (o sobre el que Google tenga beneficios conforme a cualquier ley aplicable), esto no se considerará una renuncia formal a los derechos por parte de Google y Google aún seguirá recibiendo los beneficios de esos derechos o recursos legales. 14.3 Si algún tribunal judicial con jurisdicción para decidir sobre este asunto determina que alguna de las disposiciones de este Contrato de licencia no es válida, se eliminará esa disposición del Contrato de licencia sin que eso afecte la validez del resto del contrato.
+
+
+
+
+
+ Las disposiciones restantes del Contrato de licencia continuarán siendo válidas y aplicables. 14.4 Usted reconoce y acepta que cada miembro del grupo de compañías de las que Google es la compañía central serán terceros beneficiarios del Contrato de licencia, y que esas otras empresas tendrán el derecho de imponer directamente cualquier disposición y ampararse en las disposiciones de este Contrato de licencia que les confieran un beneficio (o que confieran derechos a su favor).
+
+ Además de esto, ninguna otra persona o compañía serán terceros beneficiarios del Contrato de licencia. 14.5 RESTRICCIONES DE EXPORTACIÓN.
+
+ LA VERSIÓN PRELIMINAR ESTÁ SUJETA A LAS LEYES Y REGULACIONES DE EXPORTACIÓN DE LOS ESTADOS UNIDOS. DEBE CUMPLIR CON TODAS LAS LEYES Y REGULACIONES DE EXPORTACIÓN NACIONALES E INTERNACIONALES QUE SE APLIQUEN A LA VERSIÓN PRELIMINAR. ESTAS LEYES INCLUYEN RESTRICCIONES EN RELACIÓN CON LOS DESTINOS, USUARIOS FINALES Y USO FINAL. 14.6 Usted no puede asignar ni transferir el Contrato de licencia sin la aprobación previa por escrito de Google y todo intento de asignación sin dicha aprobación no tendrá validez.
+
+ No podrá delegar sus responsabilidades u obligaciones otorgados en virtud del Contrato de licencia sin la aprobación previa por escrito de Google. 14.7 El Contrato de licencia y su relación con Google conforme al Contrato de licencia se regirán por las leyes del estado de California, independientemente de los principios de conflictos entre leyes.
+
+ Usted y Google aceptan presentarse ante la jurisdicción exclusiva de los tribunales del condado de Santa Clara, California, para resolver cualquier asunto legal que pudiera surgir del Contrato de licencia. Sin perjuicio de esto, usted acepta que Google aún podrá aplicar reparaciones conforme a mandato judicial (o a un tipo equivalente de desagravio legal) en cualquier jurisdicción.
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">He leído y acepto los términos y las condiciones anteriores.</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>Contenido del documento</h2>
+      <ol>
+        <li><a href="#sdk">SDK de la versión preliminar</a></li>
+        <li><a href="#docs">Documentación para desarrolladores</a></li>
+        <li><a href="#images">Imágenes del sistema de hardware</a></li>
+      </ol>
+
+      <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  El SDK de la versión preliminar de Android M incluye herramientas de desarrollo, archivos de sistema de Android y archivos de biblioteca que lo ayudarán a probar su aplicación y las nuevas API que se incluirán en la próxima versión de la plataforma.
+ En este documento, se describe la manera de obtener los componentes que se pueden descargar de la versión preliminar para probar su aplicación.
+
+</p>
+
+
+<h2 id="sdk">SDK de la versión preliminar</h2>
+
+<p>
+  El SDK de la versión preliminar se encuentra disponible para descargarlo a través del <a href="{@docRoot}tools/help/sdk-manager.html">Administrador de SDK de Android</a>. Para obtener más información sobre cómo descargar y configurar el SDK de la versión preliminar, consulte la sección <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Configurar el SDK de la versión preliminar</a>.
+
+</p>
+
+
+<h2 id="docs">Documentación para desarrolladores</h2>
+
+<p>
+  El paquete de descarga de documentación para desarrolladores brinda información detallada de referencia sobre las API y un informe de diferencias de las API para la versión preliminar.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">Imágenes del sistema de hardware</h2>
+
+<p>
+  Estas imágenes del sistema le permiten instalar una versión preliminar de la plataforma en un dispositivo físico para realizar pruebas.
+ Al configurar un dispositivo con una de estas imágenes, puede instalar y probar su aplicación para ver cómo funciona en la próxima versión de la plataforma.
+ El proceso de instalación de una imagen del sistema en un dispositivo <em>elimina todos los datos del dispositivo</em>, por lo que debe hacer una copia de seguridad de los datos antes de instalar una imagen del sistema.
+
+
+</p>
+
+<p class="warning">
+  <b>Advertencia:</b> Las siguientes imágenes del sistema de Android son versiones preliminares y están sujetas a cambios. El uso que haga de estas imágenes del sistema se rige por el Contrato de licencia de la versión preliminar del SDK de Android.
+ Las imágenes del sistema de la versión preliminar de Android no son versiones estables y pueden contener errores y defectos que pueden generar daños en sus sistemas informáticos, dispositivos y datos.
+
+ Las imágenes del sistema de la versión preliminar de Android no se someten a las mismas pruebas que el OS de fábrica y podrían hacer que el teléfono, y las aplicaciones y los servicios instalados dejen de funcionar.
+
+
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">Instalar una imagen en un dispositivo</h3>
+
+<p>
+  Si desea utilizar una imagen del dispositivo para realizar pruebas, debe instalarla en un dispositivo compatible. Siga las instrucciones que se ofrecen a continuación para instalar una imagen del sistema:
+
+</p>
+
+<ol>
+  <li>Descargue y descomprima uno de los paquetes de imágenes del sistema que se enumeran aquí.</li>
+  <li>Realice una copia de seguridad de los datos del dispositivo que desee conservar.</li>
+  <li>Siga las instrucciones que se describen en el sitio <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+ para actualizar la imagen en su dispositivo.
+</li>
+</ol>
+
+<p class="note">
+  <strong>Nota:</strong> Cuando haya actualizado un dispositivo de desarrollo con la imagen del sistema de la versión preliminar, se actualizará automáticamente con la próxima versión preliminar a través de actualizaciones OTA.
+
+</p>
+
+<h3 id="revertDevice">Restablecer las especificaciones de fábrica en un dispositivo</h3>
+
+<p>
+  Si desea desinstalar la versión preliminar y restablecer las especificaciones de fábrica en un dispositivo, visite el sitio <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> y descargue la imagen con la que desea actualizar su dispositivo.
+
+ Siga las instrucciones que se describen en esa página para actualizar la imagen en su dispositivo.
+
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/es/preview/index.jd b/docs/html-intl/intl/es/preview/index.jd
index aae8e4c..547b5b0 100644
--- a/docs/html-intl/intl/es/preview/index.jd
+++ b/docs/html-intl/intl/es/preview/index.jd
@@ -30,7 +30,7 @@
 
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
 
       </div>
     </div>
diff --git a/docs/html-intl/intl/ja/index.jd b/docs/html-intl/intl/ja/index.jd
index 3084b24..a11136d 100644
--- a/docs/html-intl/intl/ja/index.jd
+++ b/docs/html-intl/intl/ja/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">次期バージョンの Android に向けて準備しましょう。
         Nexus 5、6、9、Nexus Player でアプリをテストします。 </p>
 
@@ -32,7 +29,7 @@
         </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
 
       </div>
     </div>
diff --git a/docs/html-intl/intl/ja/preview/download.jd b/docs/html-intl/intl/ja/preview/download.jd
index 67b1bc4..7f6f499 100644
--- a/docs/html-intl/intl/ja/preview/download.jd
+++ b/docs/html-intl/intl/ja/preview/download.jd
@@ -164,14 +164,15 @@
   <div id="qv">
     <h2>本書の内容</h2>
       <ol>
-        <li><a href="#sdk">Preview SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">デベロッパー ドキュメント</a></li>
         <li><a href="#images">ハードウェアのシステム イメージ</a></li>
       </ol>
 
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+           <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -184,7 +185,7 @@
 </p>
 
 
-<h2 id="sdk">Preview SDK</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   Preview SDK <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK マネージャー</a>経由でダウンロードできます。Preview SDK のダウンロードと設定の詳細については、<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Set Up the Preview SDK</a> をご覧ください。
@@ -204,11 +205,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1 
     </td>
   </tr>
 </table>
@@ -240,34 +241,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/ja/preview/download_mp2.jd b/docs/html-intl/intl/ja/preview/download_mp2.jd
new file mode 100644
index 0000000..67b1bc4
--- /dev/null
+++ b/docs/html-intl/intl/ja/preview/download_mp2.jd
@@ -0,0 +1,359 @@
+page.title=ダウンロード
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">Android Preview SDK のコンポーネントをダウンロード、インストールする前に、次の利用規約に同意する必要があります。
+</p>
+
+    <h2 class="norule">利用規約</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+以下は、Android SDK Preview の使用許諾契約です(以下「本契約」)。
+
+1.はじめに
+
+1.1 Android SDK Preview(以下、本契約で「Preview」という。具体的には利用可能な場合には Android システム ファイル、パッケージ型 API、Preview ライブラリ ファイルを含む)は、本契約の規定に従ってライセンス許可されます。本契約では、デベロッパーの Preview の使用に関して、デベロッパーと Google の間で法的拘束力のある契約を結びます。
+
+1.2 「Android」とは、Android オープン ソース プロジェクト(http://source.android.com/ にて随時更新)にて利用可能な、端末向けの Android ソフトウェア スタックを意味します。
+
+1.3 「Google」とは、1600 Amphitheatre Parkway, Mountain View, CA 94043, United States に主たる事業所を有するデラウェア州法人である Google Inc. を意味します。
+
+2.本契約の同意
+
+2.1 Preview を使用するには、まず本契約に同意する必要があります。本契約に同意しない場合は Preview を使用できません。
+
+2.2 同意するかまたは Preview を使用するためにクリックすると、本契約に同意したことになります。
+
+2.3 米国またはその他の国(デベロッパーが居住している国かまたはデベロッパーが Preview を使用する国を含む)の法律により Preview の使用を禁止されている人である場合、Preview を使用することも、使用許諾契約に同意することもできません。
+
+2.4 雇用主またはその他の事業体を代表または代理して本契約に拘束されることに同意し Preview を企業または組織の内部で使用する場合、担当者の雇用主またはその他の事業体を本契約に法的に拘束する完全な法的権限を有していることを表明および保証するものとします。担当者が必要な権限を有していない場合は、担当者の雇用主またはその他の事業体を代表または代理して、本契約に同意することも、Preview を使用することもできません。
+
+3.Google Preview ライセンス
+
+3.1 本契約の規定に従い、Google は Android プラットフォーム上で実行するアプリケーションの開発に Preview を個人的にもしくは企業または組織の内部で使用するための、ロイヤリティ フリーな、譲渡不可で、非排他的な、サブライセンス不可の、限定された、取り消し可能なライセンスを付与するものとします。
+
+3.2 Preview に関するすべての法的権利、所有権、利益(Preview に含まれる知的財産権を含む)は Google またはサードパーティが所有するものとします。「知的財産権」とは、特許法、著作権法、営業秘密法、商標法、不当競争防止法に基づいて発生するすべての権利、およびその他のすべての所有権を意味します。デベロッパーに明示的に付与されていない権利は、すべて Google が所有します。
+
+3.3 本契約で明示的に許可されている目的以外においては、Preview を使用できません。当該のサードパーティのライセンスで必要とされる場合を除き、デベロッパーは、(a) Preview または Preview の一部をコピー(バックアップ目的を除く)、修正、改造、再配布、逆コンパイル、リバース エンジニアリング、逆アセンブルまたは派生物の作成、または(b)モバイル ハンドセットまたは個人用 PC 以外のハードウェア端末への Preview の読み込み、Preview と他のソフトウェアとの結合、または Preview の一部を組み込んだソフトウェアや端末の配布はできません。
+
+3.4 デベロッパーは、Android の断片化につながるような行為をしないことに同意します。これには、Preview から派生したソフトウェア開発キットの配布、作成への参加、宣伝を含みます(ただし必ずしもこれらには限定されません)。
+
+3.5 オープンソース ソフトウェア ライセンス下でライセンス付与された Preview のコンポーネントの使用、複製、配布は、本契約ではなく、そのオープンソース ソフトウェアのライセンスに準拠するものとします。デベロッパーは、許諾されるすべての権利下で、そのようなオープンソース ソフトウェア ライセンスに対して、優良ライセンシーのままでいることに同意し、そのような権利を終了、停止、または違反する可能性のあるいかなる行為も差し控えることに同意するものとします。
+
+3.6 デベロッパーは、Google が提供する Preview の形式および性質は事前の通知なしに変更される場合があり、今後リリースされる Preview のバージョンでは、以前のバージョンの Preview で開発されたアプリケーションとの互換性がない可能性があることに同意します。デベロッパーは、Google が事前の通知なく、Google の単独の裁量でデベロッパーまたはユーザーへの Preview(または Preview 内の一部の機能)の提供を(恒久的または一時的に)停止する場合があることに同意します。
+
+3.7 本契約のいかなる部分も、Google のいかなる商標名、商標、サービスマーク、ロゴ、ドメイン名、またはその他のブランド識別表示を使用する権利もデベロッパーに付与するものではありません。
+
+3.8 デベロッパーは、Preview に添付または収録されているすべての知的財産権に関する通知(著作権および商標の通知を含む)の削除、隠ぺい、改ざんを行わないことに同意します。
+
+4.デベロッパーによる Preview の使用
+
+4.1 Google は、本契約に基づき Preview を使用してデベロッパーが開発したソフトウェア アプリケーションに関して、デベロッパー(またはデベロッパーのライセンサー)からいかなる権利、所有権、または利益(当該アプリケーションに含まれる知的財産権を含む)も取得するものではないことに同意します。
+
+4.2 デベロッパーは、Preview を(a)本契約、および(b)該当する司法管轄区における適用される法律、規則、または一般に認められた慣行またはガイドライン(米国またはその他の該当国におけるデータまたはソフトウェアの輸出入に関する法律を含む)で認められている目的にのみ使用することに同意します。
+
+4.3 Preview を使用してアプリケーションを開発する場合、デベロッパーはユーザーのプライバシーおよび法的権利を保護することに同意します。ユーザーからデベロッパーにユーザー名、パスワード、またはその他のログイン情報または個人情報が提供される場合、デベロッパーは、情報がデベロッパーのアプリケーションに提供されることをユーザーに認識させ、当該ユーザーについてプライバシーに関する法的に十分な通知および保護を行わなければなりません。デベロッパーのアプリケーションに個人情報または秘密情報が保存される場合、この保存は保護された方法で行われなければなりません。ユーザーからデベロッパーのアプリケーションに Google アカウントの情報が提供された場合、デベロッパーのアプリケーションでは、ユーザーが許可したタイミングで、かつユーザーが許可した限定された目的にのみ、当該情報を使用してユーザーの Google アカウントにアクセスすることが認められるものとします。
+
+4.4 デベロッパーは、Preview に関して、第三者(Google、およびあらゆる携帯電話会社を含むが、これらに限定されない)のサーバー、ネットワーク、またはその他の財産またはサービスへの妨害、中断、損害、または許可されていない態様でのアクセスとなる行為(そのような行為に該当する対象製品の開発または販売 / 配布を含む)に関与しないことに同意します。
+
+4.5 デベロッパーは、デベロッパーが Android および Android のアプリケーションを介して作成、送信、表示するデータ、コンテンツ、リソース、および自身の行為の結果(Google に発生する可能性のあるあらゆる損失および損害を含む)について、自身が単独で責任を負うこと(および Google がこれについてデベロッパーまたはいかなる第三者に対しても一切責任を負わないこと)に同意します。
+
+4.6 デベロッパーは、本契約、適用される第三者の契約もしくは利用規約、または適用される法律もしくは規則に基づく自身の義務に違反したこと、および当該違反の結果(Google または第三者に発生したあらゆる損失および損害を含む)について、自身が単独で責任を負うこと(および Google がこれについてデベロッパーまたはいかなる第三者に対しても一切責任を負わないこと)に同意します。
+
+4.7 Preview は開発中であり、デベロッパーによるテスティングやフィードバックは開発プロセスの重要な一部となります。デベロッパーは、Preview の使用により、一部の機能の実装が開発中であると認識し、Preview が安定したリリースの完全な機能性を持つことに依存すべきでないことを認識するものとします。本 Preview は、公式の Android SDK のリリース後はサポート対象でなくなるため、デベロッパーは、Preview を使用するいかなるアプリケーションも公然と配布または引き渡さないことに同意するものとします。
+
+5.デベロッパーの資格情報
+
+5.1 デベロッパーは、Google が発行した、またはデベロッパー自身で選択した、自身のデベロッパー用資格情報の秘密を保持する責任を負うこと、および自身のデベロッパー用資格情報のもとで開発されたすべてのアプリケーションについて単独で責任を負うことに同意します。
+
+6.プライバシーおよび情報
+
+6.1 Google は、Preview の継続的な技術革新と改良のために、ソフトウェアから特定の使用状況統計情報(一意識別子、関連する IP アドレス、ソフトウェアのバージョン番号、Preview のどのツール/サービスがどのように使用されているかに関する情報を含むが、これらに限定されない)を収集できます。この情報が収集される前に、Preview に通知が表示され、デベロッパーの同意が求められます。デベロッパーが同意しない場合は、情報は収集されません。
+
+6.2 収集されるデータは、Preview の改良のために集約された形で精査され、Google のプライバシー ポリシー(http://www.google.com/policies/privacy/)に従って管理されます。
+
+7.第三者のアプリケーション
+
+7.1 デベロッパーが、Preview を使用して第三者が開発したアプリケーションを実行する、あるいは第三者から提供されたデータ、コンテンツ、リソースにアクセスする場合、デベロッパーは、Google がそれらのアプリケーション、データ、コンテンツ、リソースについて責任を負わないことに同意します。デベロッパーは、そのような第三者のアプリケーションを介してアクセスするすべてのデータ、コンテンツ、リソースについては、それらを生成した者が単独で責任を負うものであり、Google はそれらの第三者のアプリケーション、データ、コンテンツ、またはリソースの使用もしくはアクセスによって生じたあらゆる損失および損害について一切責任を負わないことを理解します。
+
+7.2 デベロッパーは、そのような第三者のアプリケーションを介して表示されるデータ、コンテンツ、リソースは、提供者(あるいは代理の第三者または事業体)が所有する知的財産権で保護されている場合があることを認識するものとします。デベロッパーは、当該所有者からの明確な許可がない限り、それらのデータ、コンテンツ、リソース(全体または一部)の変更、貸与、賃貸、担保、配布または派生物の作成を行うことはできません。
+
+7.3 デベロッパーは、そのような第三者のアプリケーション、データ、コンテンツまたはリソースの使用が、デベロッパーと当該第三者間の別の規約に従うものであることを認識するものとします。
+
+8.Google API の使用
+
+8.1 Google API
+
+8.1.1 API を使用して Google からデータを取得する場合、デベロッパーは、そのデータは、Google またはデータを提供する事業体(あるいは代理の第三者または事業体)が所有する知的財産権で保護されている場合があることを認識するものとします。そのような API の使用は追加の利用規約に従うものとします。デベロッパーは、当該の利用規約による許可がない限り、そのデータ(全体または一部)の変更、貸与、賃貸、担保、配布または派生物の作成を行うことはできません。
+
+8.1.2 デベロッパーは、API を使用して Google からユーザーのデータを取得する場合、ユーザーが明示的に同意した場合のみ、およびユーザーが許可したタイミングとその目的にのみ、データを取得できることを理解し、同意します。
+
+9.本契約の終了
+
+9.1 本契約は、下記の規定に従ってデベロッパーまたは Google のいずれかによって解約されるまで、継続して適用されるものとします。
+
+9.2 デベロッパーが本契約の解約を希望する場合は、Preview および関連するデベロッパー資格情報の使用を停止することで、契約を終了するものとします。
+
+9.3 Google は、理由の有無にかかわらず、書面で通知することでいつでもデベロッパーとの本契約を解約することができます。
+
+9.4 本契約は事前の通知またはその他の措置なく、次のうち早い方に自動的に終了します。
+(A)Google が、デベロッパーが居住している国またはデベロッパーがサービスを使用する国での Preview または Preview の一部の配布を停止したとき。
+(B)Google が Android SDK の最終バージョンをリリースしたとき。
+
+9.5 本契約が終了すると、本契約で付与されていたライセンスは終了し、デベロッパーは速やかに Preview のすべての使用を停止するものとし、第 10 条、第 11 条、第 12 条、第 14 条の規定は無期限に効力を有するものとします。
+
+10.免責事項
+
+10.1 デベロッパーは、デベロッパーによる Preview の使用はデベロッパー自身の責任において行うものであること、および Preview は「現状有姿」かつ「提供可能な限りにおいて」、Google からのいかなる種類の保証もなく提供されるものであることを明示的に理解し、これに同意します。
+
+10.2 デベロッパーによる Preview および Preview の使用を通じてダウンロードまたはその他の方法で取得されたマテリアルの使用は、デベロッパー自身の裁量および責任において行うものであり、当該使用の結果として生じるデベロッパーのコンピュータ システムもしくはその他の端末への損害またはデータの喪失についての責任はデベロッパーが単独で負います。前述を制限することなく、Preview は安定したリリースではなく、コンピュータやその他の端末の利用の完全な回復不可能な損失を含む、重大な損害を引き起こす可能性のあるエラー、欠陥、およびセキュリティ上の脆弱性が含まれている可能性があることを理解します。
+
+10.3 Google はまた、商品性、特定目的への適合性、および権利侵害がないことの黙示的な保証および条件を含む(ただしこれらに限定されない)、明示的か黙示的かを問わずあらゆる種類のすべての保証および条件を明示的に否定します。
+
+11.責任の制限
+
+11.1 デベロッパーは、Google、その子会社および関連会社、ならびにそのライセンサーが、デベロッパーに発生した直接損害、間接損害、偶発的損害、特別損害、結果的損害、または懲罰的損害(データの喪失を含む)について、Google またはその代表者が当該損失が発生する可能性について告知されていたかどうか、または知っていたはずであるかどうかにかかわらず、いかなる責任法理のもとでもデベロッパーに対して責任を負わないことを明示的に理解し、これに同意します。
+
+12.補償
+
+12.1 法律で認められる最大限の範囲内において、デベロッパーは、(a)デベロッパーが Preview を使用したこと、および(b)デベロッパーが Preview で開発したアプリケーションが他者のいかなる知的財産権を侵害していること、または他者の名誉を毀損している、もしくは他者のパブリシティ権もしくはプライバシー権を侵害していること、および(c)デベロッパーが本契約に違反したことから発生したあらゆる申し立て、普通法上の訴訟、衡平法上の訴訟、または法的手続き、ならびにあらゆる損失、責任、損害、費用、および経費(合理的な弁護士報酬を含む)について、Google、その関連会社、ならびに当該各社の取締役、役員、従業員、代理人を防御し、補償し、免責することに同意します。
+
+13.契約の変更
+
+13.1 Google は、Preview の新しいバージョンを配布することにより、いつでも本契約を変更することができます。変更が生じた場合、Google は、Preview の提供ウェブサイト上に使用許諾契約の改訂版を公開します。
+
+14.法的一般条項
+
+14.1 本契約は、デベロッパーと Google の間の法的な合意のすべてを表し、デベロッパーによる Preview の使用(別の契約下で Google が提供するサービスを除く)に適用され、Preview に関するデベロッパーと Google の間のあらゆる事前の合意に完全に取って代わるものです。
+
+14.2 デベロッパーは、Google が本契約に定める(または適用される法律のもとで Google が享受できる)法的な権利または救済措置を行使または執行しなかった場合でも、Google の権利が正式に放棄されたとはみなされないこと、および Google が以後も引き続き当該権利および救済措置を行使または執行できることに同意します。
+
+14.3 本件について判断を下す管轄権を有する司法裁判所によって、本契約のいずれかの条項が無効と判断された場合、当該条項は、本契約の残りの部分に影響を与えることなく本契約から削除されるものとします。本契約の残りの条項は、以後も引き続き有効かつ執行可能であるものとします。
+
+14.4 デベロッパーは、Google が親会社となっている各グループ企業が、本契約の第三受益者となること、および当該企業が、当該企業に利益(または受益権)を付与する本契約の条項を直接執行する、また当該条項に依拠する権利を有することを了承し、これに同意します。上記以外のいかなる人または法人も、本契約の第三受益者とはならないものとします。
+
+14.5 輸出規制。Preview は、米国輸出管理法令の対象です。デベロッパーは、Preview に適用されるすべての国内および国際の輸出管理法令に従わなければなりません。これらの法律には、仕向け地、ユーザー、および最終用途に関する制限が含まれます。
+
+14.6 デベロッパーは、Google から事前に書面で承認を得ずに、本契約を譲渡または移転することはできません。また、そのような承認を得ずに計画された譲渡はすべて無効になります。デベロッパーは、Google から事前に書面で承認を得ずに、本契約に基づく自身の責任または義務を他者に委任してはなりません。
+
+14.7 本契約あるいは本契約に基づくデベロッパーと Google の関係から発生または関連するすべての申し立ては、米国カリフォルニア州の抵触法を除いて、カリフォルニア州法に準拠するものとします。デベロッパーおよび Google は、本契約あるいは本契約に基づくデベロッパーと Google の関係から発生または関連する法的事項の解決について、米国カリフォルニア州サンタクララ郡に所在の連邦裁判所または州立裁判所が専属管轄権を有することに合意します。上記にかかわらず、デベロッパーは、Google が任意の司法管轄区において差し止め命令による救済(または同等の緊急法的救済)を求める申し立てを行うことが認められることに同意します。
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">上記の利用規約を読み、同意します。</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>本書の内容</h2>
+      <ol>
+        <li><a href="#sdk">Preview SDK</a></li>
+        <li><a href="#docs">デベロッパー ドキュメント</a></li>
+        <li><a href="#images">ハードウェアのシステム イメージ</a></li>
+      </ol>
+
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  Android M Preview SDK には、アプリとプラットフォームの次期リリースで提供される新しい API とのテストに役立つ開発ツール、Android システム ファイル、ライブラリ ファイルが含まれています。
+このドキュメントでは、アプリのテスト用にダウンロードできる Preview のコンポーネントを入手する方法について説明します。
+
+</p>
+
+
+<h2 id="sdk">Preview SDK</h2>
+
+<p>
+  Preview SDK <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK マネージャー</a>経由でダウンロードできます。Preview SDK のダウンロードと設定の詳細については、<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Set Up the Preview SDK</a> をご覧ください。
+
+</p>
+
+
+<h2 id="docs">デベロッパー ドキュメント</h2>
+
+<p>
+  デベロッパー ドキュメントのダウンロード パッケージでは、詳細な Preview の API リファレンス情報や API の比較レポートが提供されます。
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+<h2 id="images">ハードウェアのシステム イメージ</h2>
+
+<p>
+  これらのシステム イメージでは、テスト用に物理端末にプラットフォームのプレビュー バージョンをインストールできます。
+端末にこれらのイメージを 1 つ以上設定すると、アプリをインストールして、プラットフォームの次期バージョンでアプリがどのように動作するかをテストできます。
+端末にシステム イメージをインストールするプロセスでは、<em>端末からすべてのデータが削除</em>されるため、システム イメージのインストール前にデータをバックアップする必要があります。
+
+
+</p>
+
+<p class="warning">
+  <b>警告:</b> 次の Android システム イメージはプレビュー版であり、今後変更される可能性があります。デベロッパーによるシステム イメージの使用は、Android SDK Preview 使用許諾契約に準拠するものとします。
+Android Preview システム イメージは安定したリリースではなく、お使いのコンピュータ システム、端末、データに影響を与える可能性のあるエラーや欠陥が含まれている場合があります。
+
+プレビュー版の Android システム イメージは工場出荷版の OS と同等のテストを受けておらず、お使いの電話やインストールされているサービス、アンインストールの動作停止を引き起こす場合があります。
+
+
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">端末にイメージをインストールする</h3>
+
+<p>
+  テスト用に端末イメージを使用するには、互換性のある端末にインストールする必要があります。次の手順に従って、システム イメージをインストールします。
+
+</p>
+
+<ol>
+  <li>この一覧の中からいずれかのシステム イメージ パッケージをダウンロードして、解凍します。</li>
+  <li>保持するデータを端末からバックアップします。</li>
+  <li>
+<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+ の手順に従って端末にイメージをフラッシュします。</li>
+</ol>
+
+<p class="note">
+  <strong>注:</strong> 開発用端末に Preview のシステム イメージをフラッシュすると、OTA アップデートを通じて次のプレビュー リリースに自動的にアップグレードされます。
+
+</p>
+
+<h3 id="revertDevice">端末を工場出荷時の仕様に戻す</h3>
+
+<p>
+  Preview をアンインストールして、工場出荷時の仕様に戻すには、
+<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> にアクセス
+して、端末にフラッシュするイメージをダウンロードします。同じページの手順に従って端末にイメージをフラッシュします。
+
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/ja/preview/index.jd b/docs/html-intl/intl/ja/preview/index.jd
index e44a42a..2e84aa3 100644
--- a/docs/html-intl/intl/ja/preview/index.jd
+++ b/docs/html-intl/intl/ja/preview/index.jd
@@ -30,7 +30,7 @@
 
          <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html-intl/intl/ko/index.jd b/docs/html-intl/intl/ko/index.jd
index 34c14ec..d95d698 100644
--- a/docs/html-intl/intl/ko/index.jd
+++ b/docs/html-intl/intl/ko/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">Android의 다음 버전을 만나볼 준비가
         되셨습니까? 여러분의 앱을 Nexus 5, 6, 9 및 Player에서 테스트해보십시오. </p>
 
@@ -32,7 +29,7 @@
         </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
   </div>
diff --git a/docs/html-intl/intl/ko/preview/download.jd b/docs/html-intl/intl/ko/preview/download.jd
index ff9dd7e..d92453a 100644
--- a/docs/html-intl/intl/ko/preview/download.jd
+++ b/docs/html-intl/intl/ko/preview/download.jd
@@ -164,14 +164,15 @@
   <div id="qv">
     <h2>이 문서의 내용</h2>
       <ol>
-        <li><a href="#sdk">미리 보기 SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">개발자 관련 문서</a></li>
         <li><a href="#images">하드웨어 시스템 이미지</a></li>
       </ol>
 
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+           <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -184,7 +185,7 @@
 </p>
 
 
-<h2 id="sdk">미리 보기 SDK</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   미리 보기 SDK는 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>를 통해 다운로드할 수 있습니다. 미리 보기 SDK를 다운로드하고 구성하는 데 관한 자세한 정보는 <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">미리 보기 SDK 설정하기</a>를 참조하십시오.
@@ -204,11 +205,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -241,34 +242,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/ko/preview/download_mp2.jd b/docs/html-intl/intl/ko/preview/download_mp2.jd
new file mode 100644
index 0000000..ff9dd7e
--- /dev/null
+++ b/docs/html-intl/intl/ko/preview/download_mp2.jd
@@ -0,0 +1,360 @@
+page.title=다운로드
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">Android 미리 보기 SDK의 구성 요소를 다운로드하고 설치하기 전에 우선 다음과 같은 사용 약관에 동의해야 합니다.
+</p>
+
+    <h2 class="norule">사용 약관</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+이것은 Android SDK 미리 보기 라이선스 계약서입니다(이하 "라이선스 계약").
+
+1. 개요
+
+1.1 Android SDK 미리 보기(본 라이선스 계약에서는 "미리 보기"라고 칭하며, 구체적으로 Android 시스템 파일, 패키지 API 및 미리 보기 라이브러리 파일이 이용 가능한 경우 및 이용 가능하게 전환된 경우 이를 포함한 것을 가리킴)는 본 라이선스 계약 조건에 따라 계약자에게 사용을 허여합니다. 본 라이선스 계약은 미리 보기 사용과 관련하여 계약자와 Google 간에 법적 구속력이 있는 계약을 체결합니다.
+
+1.2 "Android"는 기기를 위한 Android 소프트웨어 스택을 의미합니다. 이는 http://source.android.com/ URL에 위치하며 수시로 업데이트되는 Android 오픈 소스 프로젝트에서 제공됩니다.
+
+1.3 "Google"은 미국 1600 Amphitheatre Parkway, Mountain View, CA 94043에 본사를 두고 있는 델라웨어주 법인인 Google Inc.를 의미합니다.
+
+2. 라이선스 계약에 동의
+
+2.1 이 미리 보기를 사용하려면, 먼저 라이선스 계약에 동의해야 합니다. 이 라이선스 계약에 동의하지 않고 미리 보기를 사용해서는 안 됩니다.
+
+2.2 수락을 클릭하고/거나 미리 보기를 사용하면 본 라이선스 계약 조건에 동의하는 것으로 간주됩니다.
+
+2.3 미국법 또는 현재 거주 중이거나 미리 보기를 사용하는 국가를 포함하여 다른 국가의 법에 따라 미리 보기를 받는 것이 금지된 경우, 미리 보기를 사용할 수 없으며 본 라이선스 계약을 수락할 수 없습니다.
+
+2.4 회사 또는 단체 내에서 내부적으로 미리 보기를 사용하며 고용주 또는 기타 단체를 대신하여 본 라이선스 계약 준수에 동의하는 경우, 계약자의 고용주나 그 단체에 본 라이선스 계약에 대한 구속력을 부여할 수 있는 모든 법적 권한을 계약자가 갖고 있음을 진술하고 보증합니다. 구속력을 부여할 수 있는 법적 권한이 없을 경우, 고용주 또는 기타 단체를 대신하여 본 라이선스 계약에 동의하거나 미리 보기를 사용할 수 없습니다.
+
+3. Google이 허하는 미리 보기 라이선스
+
+3.1 본 라이선스 계약의 조건에 따라 Google은 계약자에게 로열티 없고 양도 불가능하며 비독점적이고 2차 인가를 불허하며, 한정되고 무효화할 수 있는 미리 보기 사용 권한을 허용하여 회사 또는 조직 내에서 개인적 또는 내부적으로 사용할 수 있도록 합니다. 이는 Android 플랫폼에서 실행되는 애플리케이션을 개발할 목적으로만 사용해야 합니다.
+
+3.2 계약자는 SDK에 존재하는 지적 재산권을 포함한 SDK에 대한 모든 법적인 권리, 소유권 및 이익이 Google 또는 제3자에게 있음에 동의합니다 "지적 재산권"은 모든 특허법, 저작권법, 영업비밀법, 상표법상 존재하는 모든 권리 및 기타 모든 재산권을 의미합니다. Google은 계약자에게 명시적으로 부여하지 않은 모든 권리를 보유합니다.
+
+3.3 본 라이선스 계약에 명시적으로 허용된 용도 외에는 미리 보기를 사용할 수 없습니다. 해당 제3자 라이선스 요건이 허용하는 범위를 제외하고 계약자는 미리 보기의 일부분을 (a) 복사(백업 목적 제외), 수정, 개작, 재배포, 역컴파일, 리버스 엔지니어링, 분해하거나 이를 통해 파생물을 생성하거나 (b) 개인 컴퓨터를 제외한 모바일 단말기 또는 기타 모든 하드웨어 기기에 미리 보기의 일부를 로드하거나, 미리 보기의 일부를 다른 소프트웨어와 결합하거나 미리 보기의 일부가 통합된 일체의 소프트웨어나 기기를 배포해서는 안 됩니다.
+
+3.4 계약자는 미리 보기에서 파생된 소프트웨어 개발 키트의 배포, 이러한 키트 생성에 참여 또는 홍보를 포함하되 이에 국한되지 않고, Android의 단편화를 야기하는 어떠한 행동도 취하지 않을 것임에 동의합니다.
+
+3.5 오픈 소스 소프트웨어 라이선스에 의거한 미리 보기 구성요소의 사용, 재생산, 배포에는 본 라이선스 계약이 아닌, 해당 오픈 소스 소프트웨어 라이선스의 조건이 적용됩니다. 계약자는 허용된 모든 권한 하에서 그러한 오픈 소스 소프트웨어 라이선스에 관해 충실한 피허가자로서의 자세를 견지할 것이며 그러한 권한을 종료, 일시 중단 또는 침해하는 행위를 삼갈 것을 동의합니다.
+
+3.6 계약자는 Google이 제공하는 SDK의 형태 및 특성이 사전 통지 없이 변경될 수 있음에 동의하며, 이전 버전의 미리 보기에서 개발된 애플리케이션이 이후 버전의 SDK와 호환되지 않을 수 있음에 동의합니다. 계약자는 계약자 또는 사용자에게 사전 통지 없이 SDK(또는 SDK에 포함된 기능) 제공을(영구적 또는 일시적으로) 중단할 수 있는 권한이 Google에게 있음에 동의합니다.
+
+3.7 본 라이선스 계약은 계약자에게 Google의 상표명, 상표, 서비스 표시, 로고, 도메인 이름, 기타 독특한 브랜드 특징에 대한 사용 권한을 부여하지 않습니다.
+
+3.8 계약자는 SDK에 부착되어 있거나 포함되어 있는 모든 소유권 고지 사항(저작권 및 상표 고지 사항 포함)을 제거, 변경 또는 불분명하게 만들지 않을 것에 동의합니다.
+
+4. 계약자의 미리 보기 사용
+
+4.1 Google은 본 라이선스 계약의 어떤 조항도 계약자(또는 계약자의 사용 허가자)가 미리 보기를 사용하여 개발한 소프트웨어 애플리케이션에 대한 권리, 소유권 또는 이익, 그리고 해당 애플리케이션에 존재하는 모든 지적 재산권을 부여하지 않는다는 점에 동의합니다.
+
+4.2 계약자는 (a) 본 라이선스 계약 그리고 (b) 모든 준거법, 규정 또는 관련 관할권 내에서 일반적으로 수용되는 관행 또는 지침(미국 또는 기타 관련 국가로/에서의 데이터 또는 소프트웨어 수출과 관련된 모든 법률 포함)에서 허용하는 용도에 한하여 미리 보기를 사용하고 애플리케이션을 작성하는 것에 동의합니다.
+
+4.3 계약자는 일반 대중 사용자를 대상으로 미리 보기를 사용하여 애플리케이션을 개발하는 경우, 해당 사용자의 프라이버시 및 법적 권리를 보호하는 것에 동의합니다. 사용자가 계약자에게 사용자 이름, 비밀번호 또는 기타 로그인 정보나 개인 정보를 제공하는 경우, 계약자는 제공된 정보가 자신의 애플리케이션에 제공된다는 사실을 사용자에게 알려야 하며, 반드시 법적으로 적절한 개인정보 보호정책 고지 및 보호를 해당 사용자에게 제공해야 합니다. 애플리케이션에서 사용자가 제공한 개인정보나 민감한 정보를 저장하는 경우, 이를 안전하게 처리해야 합니다. 사용자들이 애플리케이션에 Google 계정 정보를 제공하는 경우, 애플리케이션은 해당 사용자의 Google 계정에 액세스하는 목적으로만, 그리고 각 사용자가 허용한 범위 내의 한정된 목적으로만 이러한 정보를 사용해야 합니다.
+
+4.4 계약자는 Google 또는 기타 모든 타사의 서버, 네트워크 또는 기타 모든 재산 또는 서비스를 허가 없이 방해, 교란, 손상 또는 액세스하는 애플리케이션의 개발 또는 배포를 포함한 하등의 행위에 미리 보기를 이용하지 않을 것임을 동의합니다.
+
+4.5 계약자는 자신이 Android 및/또는 Android용 애플리케이션을 통해 생성, 전송 또는 표시하는 모든 데이터, 콘텐츠 또는 리소스 그리고 그로 인한 결과(Google이 입을 수 있는 모든 피해나 손실 포함)에 대해 전적으로 책임이 있다는 것(그리고 Google은 계약자 또는 모든 제3자에 대한 책임이 없다는 것)에 동의합니다.
+
+4.6 계약자는 본 라이선스 계약, 모든 해당 제3자 계약 또는 서비스 약관, 또는 모든 준거법 또는 규정에 의거한 계약자 의무 위반, 그리고 그로 인한 결과(Google 또는 제3자가 입을 수 있는 모든 피해나 손실 포함)에 전적으로 책임이 있다는 것(그리고 Google은 계약자 또는 모든 제3자에 대한 책임이 없다는 것)에 동의합니다.
+
+4.7 이 미리 보기는 현재 개발 단계에 있으며, 계약자의 테스트와 피드백은 그러한 개발 과정에 중요한 부분을 차지합니다. 미리 보기를 사용함으로써 계약자는 일부 기능의 구현은 아직 개발 중인 상태이며 미리 보기가 안정된 릴리스처럼 완벽하게 기능할 것이라 믿고 사용해서는 안 된다는 점을 인지하는 것으로 간주합니다. 계약자는 이 미리 보기를 사용한 애플리케이션을 공개적으로 배포 또는 배송하지 않기로 동의합니다. 이 미리 보기는 공식 Android SDK가 출시된 이후에는 더 이상 지원되지 않기 때문입니다.
+
+5. 계약자의 개발자 자격 증명
+
+5.1 계약자는 Google이 발급했거나 자신이 선택한 모든 개발자 자격 증명에 대한 기밀성을 유지할 책임이 있으며 계약자의 개발자 자격 증명 하에 개발된 모든 애플리케이션에 대한 전적인 책임이 있음에 동의합니다.
+
+6. 개인정보 보호정책 및 정보
+
+6.1 미리 보기를 지속적으로 혁신하고 개선하기 위해, Google은 고유 식별자, 관련 IP 주소, 소프트웨어 버전 번호, 미리 보기에서 사용 중인 도구 및/또는 서비스와 도구의 사용법에 대한 정보를 포함하되 이에 국한되지 않고 소프트웨어에서 특정 사용량 통계 정보를 수집할 수 있습니다. 그러한 정보를 수집하기 전에 미리 보기는 계약자에게 이를 통지하고 동의를 구할 것입니다. 계약자가 동의하지 않을 경우 정보를 수집하지 않습니다.
+
+6.2 수집된 데이터는 모두 취합된 형태로 미리 보기 개선을 위해 검토되며, Google의 개인정보 보호정책에 따라 유지 관리됩니다. 이 정보는 http://www.google.com/policies/privacy/를 참조하십시오.
+
+7. 제3자 애플리케이션
+
+7.1 제3자가 개발한 애플리케이션을 실행하거나 제3자가 제공한 데이터, 콘텐츠 또는 리소스에 액세스하기 위해 미리 보기를 사용하는 경우, 계약자는 Google이 그러한 애플리케이션, 데이터, 콘텐츠 또는 리소스에 대한 책임이 없음에 동의합니다. 계약자는 그러한 제3자 애플리케이션을 통해 자신이 액세스한 모든 데이터, 콘텐츠 또는 리소스에 대한 책임은 그것을 만든 사람에게 있음에 동의합니다. 또한 계약자가 그러한 모든 제3자 애플리케이션, 데이터, 콘텐츠 또는 리소스를 사용하거나 액세스함으로써 비롯된 모든 피해나 손실에 대한 책임이 Google에게 없음에 동의합니다.
+
+7.2 그러한 제3자 애플리케이션을 통해 계약자에게 제공된 데이터, 콘텐츠 그리고 리소스는 그것을 제공한 제공자(또는 제공자를 대신하는 기타 개인 또는 기업)가 소유한 지적 재산권에 의해 보호될 수 있음을 유의해야 합니다. 그러한 데이터, 콘텐츠 또는 리소스(전부 또는 일부)를 수정, 임대, 리스, 대여, 판매, 배포하거나 이를 기반으로 파생물을 생성해서는 안 됩니다. 단, 관련 소유자로부터 그러한 작업을 수행해도 좋다는 허락을 받은 경우에는 예외입니다.
+
+7.3 계약자는 그러한 제3자 애플리케이션, 데이터, 콘텐츠 또는 리소스의 사용은 계약자와 관련 제3자 간에 체결하는 별도의 계약 조건의 적용을 받는다는 것을 인정합니다.
+
+8. Google API 사용
+
+8.1 Google Data API
+
+8.1.1 Google에서 데이터를 검색하기 위해 API를 사용하는 경우, 그러한 데이터가 Google 또는 데이터를 제공하는 당사자(또는 당사자를 대신하는 기타 개인 또는 기업)가 소유한 지적 재산권에 의해 보호될 수 있음을 인정합니다. 그러한 API를 사용하는 경우, 추가적인 서비스 약관의 적용을 받을 수 있습니다. 관련 서비스 약관에 허용되지 않은 한, 그러한 데이터(전부 또는 일부)를 변경, 임대, 리스, 대여, 판매, 배포하거나 이를 기반으로 파생물을 생성해서는 안 됩니다.
+
+8.1.2 Google에서 사용자 데이터를 검색하기 위해 API를 사용하는 경우, 계약자는 사용자로부터 명시적인 동의를 얻은 경우에 한하여, 그리고 해당 사용자가 허용한 범위 내의 한정된 목적으로만 데이터를 검색해야 합니다.
+
+9. 라이선스 계약 종료
+
+9.1 본 라이선스 계약은 계약자 또는 Google에 의해 아래와 같은 조건 하에 종료될 때까지 계속 적용됩니다.
+
+9.2 계약자가 라이선스 계약을 종료하고자 하는 경우, 미리 보기 및 관련 개발자 자격 증명 일체의 사용을 중단하는 것으로 그러한 의사를 피력할 수 있습니다.
+
+9.3 Google은 언제든 이유 여하를 불문하고 계약자에게 통고하여 라이선스 계약을 종료할 수 있습니다.
+
+9.4 본 라이선스 계약은 통보 또는 여타의 행위 없이도 자동으로 종료됩니다. 이에 해당되려면 다음과 같은 조건이 수반되어야 합니다.
+(A) Google이 계약자가 거주하는 국가 또는 계약자가 서비스를 사용하는 지역에서 미리 보기 또는 미리 보기의 특정 부분 제공을 중지하는 경우 및
+(B) Google이 Android SDK의 최종 릴리스 버전을 발행하는 경우.
+
+9.5 본 라이선스 계약이 종료되면 라이선스 계약으로 계약자에게 허용한 라이선스가 취소되며, 이에 따라 계약자는 미리 보기 사용을 즉시 모두 중단해야 하고 제 10, 11, 12 및 14절의 조항이 기한 없이 유지됩니다.
+
+10. 면책 조항
+
+10.1 계약자는 미리 보기 이용에 대한 위험 부담이 전적으로 본인에게 있으며, Google이 일체의 보증 없이 미리 보기를 "있는 그대로" 그리고 "이용 가능한" 상태로 제공한다는 것을 분명히 이해하고 동의합니다.
+
+10.2 미리 보기 이용 및 이용 과정에서 다운로드하거나 얻게 되는 모든 자료를 사용하는 것은 본인의 재량에 따르며 이에 대한 위험 부담이 전적으로 본인에게 있으며, 그러한 사용으로 인해 발생하는 컴퓨터 시스템 또는 다른 기기의 손상 또는 데이터 손실에 대한 책임은 전적으로 본인에게 있습니다. 전술한 조항을 제한하지 않는 범위 내에서 계약자는 미리 보기가 안정된 릴리스가 아니며 오류, 결함 및 보안 취약성이 포함되어 있을 수 있어 그 결과로 중대한 손상을 유발할 수 있다는 점을 이해하는 것으로 간주합니다. 여기에는 계약자의 컴퓨터 시스템 또는 기타 기기의 완전하고 돌이킬 수 없는 손실도 포함됩니다.
+
+10.3 더 나아가, Google은 상품성, 특정 목적에 대한 적합성 및 비침해의 묵시적 보증 등을 포함하되 이에 국한되지 않고 명시적이든 묵시적이든 모든 종류의 보증 및 조건을 명시적으로 부인합니다.
+
+11. 책임 한계
+
+11.1 계약자는 계약자에게 발생할 수 있는 직접, 간접, 부수적, 특별, 결과적 또는 징벌적 손해에 대해 그 어떤 책임 이론에 근거해서도 Google, 해당 자회사, 계열사 및 사용 허가자가 어떠한 책임도 지지 아니함을 분명히 이해하고 동의합니다. 이러한 손해에는 Google 또는 해당 대리자가 이러한 손실 발생 가능성에 대해 통지를 받았거나 이러한 사항을 인식했는지에 상관없이 모든 데이터 손실이 포함됩니다.
+
+12. 면책
+
+12.1 법률에 의해 허용되는 최대한의 범위 안에서 계약자는 (a) 미리 보기 사용, (b) 계약자가 미리 보기에서 개발한 일체의 애플리케이션에서 초래된 모든 사람의 저작권, 상표, 영업비밀, 트레이드 드레스, 특허 또는 기타 지적 재산권의 침해, 또는 어떤 사람의 명예를 훼손하거나 초상권 또는 개인정보 보호정책을 침해함 또는 (C)계약자 본인이 본 라이선스 계약을 위반함으로써 발생하거나 생기는 모든 청구, 조치, 소송 또는 절차, 그리고 모든 손실, 책임, 손해, 경비(합리적인 변호사 비용 포함)로부터 Google을 옹호하고, 면책시키고, Google이 손해를 입지 않도록 하는 데 동의합니다.
+
+13. 라이선스 계약 변경
+
+13.1 미리 보기의 새로운 버전을 배포할 때, Google은 본 라이선스 계약의 내용을 변경할 수 있습니다. 그러한 변경이 이뤄진 경우, Google은 미리 보기가 제공되는 웹사이트에 새로운 라이선스 계약 버전을 게재할 것입니다.
+
+14. 일반 법적 조건
+
+14.1 본 라이선스 계약은 계약자와 Google 간의 모든 법적 계약을 구성하며, 계약자의 미리 보기 사용을 규제하고(별도의 서면 계약을 통해 Google이 계약자에게 제공하는 모든 서비스는 제외), 미리 보기와 관련하여 이전에 계약자와 Google이 맺은 모든 계약을 완전히 대체합니다.
+
+14.2 계약자는 Google이 라이선스 계약에 포함된(또는 관련 법률에 의해 Google이 향유하는) 법적 권리 또는 구제수단을 행사하거나 집행하지 않더라도, Google이 권리를 공식적으로 포기한 것으로 간주하지 않으며, Google이 계속해서 그러한 권리 또는 구제수단을 이용할 수 있음에 동의합니다.
+
+14.3 본 라이선스 계약의 조항이 무효라고 이 사안에 관한 판결을 할 수 있는 관할권을 가진 법원이 판결할 경우, 그 조항은 라이선스 계약의 나머지 조항에 영향을 미치지 않는 형태로 라이선스 계약에서 제거됩니다. 본 라이선스 계약의 나머지 조항은 여전히 유효하며 집행 가능합니다.
+
+14.4 계약자는 Google이 모회사가 되는 회사 그룹에 속한 각 회사가 본 라이선스 계약의 제3수익자이며, 그러한 다른 회사들이 그들에게 이익(또는 유리한 권리)을 부여하는 본 라이선스 계약의 모든 조항을 직접 행사하고 적용할 수 있는 권리를 가진다는 데 동의합니다. 그 외에는 다른 어떤 개인이나 회사도 본 라이선스 계약의 제3수익자가 될 수 없습니다.
+
+14.5 수출 규제. 미리 보기는 미국의 수출법과 규정의 적용을 받습니다. 계약자는 미리 보기에 적용되는 모든 국내 및 국제 수출법과 규정을 준수해야 합니다. 그러한 법에는 수출 대상국, 최종 사용자 및 최종 용도에 대한 제한이 포함됩니다.
+
+14.6 계약자 또는 Google은 상대 당사자의 사전 서면 승인 없이 본 라이선스 계약에서 부여된 권리를 제3자에게 양도하거나 이전할 수 없으며, 그러한 승인 없이 이루어진 양도 시도는 모두 무효입니다. 계약자는 Google의 사전 승인 없이 본 라이선스 계약 상의 책임 또는 의무를 위임할 수 없습니다.
+
+14.7 본 라이선스 계약, 그리고 본 라이선스 계약 상의 계약자와 Google의 관계는 법률 조항 간의 충돌과는 무관하게 캘리포니아주법에 의한 규제를 받습니다. 계약자와 Google은 본 라이선스 계약으로부터 발생하는 모든 법적 문제 해결을 캘리포니아주 산타 클라라(Santa Clara) 카운티 내에 소재한 전속 관할 법원에 의뢰하는 것에 동의합니다. 위 규정에도 불구하고, 계약자는 Google이 여전히 모든 관할권에서 강제 구제책(또는 동등한 유형의 긴급 법적 구제)을 신청할 수 있음에 동의합니다.
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">본인은 상기 사용 약관을 읽었으며 이에 동의합니다.</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>이 문서의 내용</h2>
+      <ol>
+        <li><a href="#sdk">미리 보기 SDK</a></li>
+        <li><a href="#docs">개발자 관련 문서</a></li>
+        <li><a href="#images">하드웨어 시스템 이미지</a></li>
+      </ol>
+
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  Android M 미리 보기 SDK에는 개발 도구, Android 시스템 파일 및 라이브러리 파일이 포함되어 있어 앱을 테스트하고 플랫폼의 다음 릴리스에 도입되는 새 API를 테스트하는 데 유용합니다.
+ 이 문서에서는 미리 보기의 다운로드할 수 있는 구성 요소를 가져와 앱을 테스트하는 방법에 대해 설명합니다.
+
+</p>
+
+
+<h2 id="sdk">미리 보기 SDK</h2>
+
+<p>
+  미리 보기 SDK는 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>를 통해 다운로드할 수 있습니다. 미리 보기 SDK를 다운로드하고 구성하는 데 관한 자세한 정보는 <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">미리 보기 SDK 설정하기</a>를 참조하십시오.
+
+</p>
+
+
+<h2 id="docs">개발자 관련 문서</h2>
+
+<p>
+  개발자 관련 문서 다운로드 패키지에서는 자세한 API 참조 정보와 미리 보기에 대한 API 차이점 보고서를 제공합니다.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">하드웨어 시스템 이미지</h2>
+
+<p>
+  이러한 시스템 이미지를 사용하면 물리적인 기기에서 플랫폼의 미리 보기 버전을 설치하여 테스트할 수 있게 해줍니다.
+ 이러한 이미지 중 한 가지로 기기를 구성하면, 앱을 설치하고 테스트하여 앱이 플랫폼의 다음 버전에서 어떤 성능을 보일지 확인할 수 있습니다.
+ 기기에 시스템 이미지를 설치하는 과정은<em>기기에서 모든 데이터를 제거하므로</em>, 시스템 이미지를 설치하기에 앞서 데이터를 백업하는 것이 좋습니다.
+
+
+</p>
+
+<p class="warning">
+  <b>경고:</b> 다음 Android 시스템 이미지는 미리 보기이며 사정에 따라 변동될 수 있습니다. 이러한 시스템 이미지를 사용할 때에는 Android SDK 미리 보기 라이선스 계약을 따라야 합니다.
+ Android 미리 보기 시스템 이미지는 안정된 릴리스가 아니며, 오류나 결함이 들어있을 수 있고 이 때문에 컴퓨터 시스템, 기기 및 데이터에 손상을 초래할 수 있습니다.
+
+ 미리 보기 Android 시스템 이미지는 공장 OS와 같은 테스트를 거치며 전화기 및 설치된 서비스와 애플리케이션의 작동이 중단되는 결과를 낳을 수 있습니다.
+
+
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">기기에 이미지 설치</h3>
+
+<p>
+  기기 이미지를 테스트용으로 사용하려면, 이를 호환되는 기기에 설치해야만 합니다. 시스템 이미지를 설치하려면 아래의 지침을 따르십시오.
+
+</p>
+
+<ol>
+  <li>여기 목록에 나열된 시스템 이미지 중 하나를 다운로드하여 압축을 해제합니다.</li>
+  <li>기기에서 보존하고자 하는 데이터를 모두 백업합니다.</li>
+  <li>이미지를 기기에 플래시하려면 <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>에 있는 지침을 따릅니다.
+
+</li>
+</ol>
+
+<p class="note">
+  <strong>참고:</strong> 일단 개발 기기에 미리 보기 시스템 이미지를 플래시하고 나면 이것은 OTA(over-the-air) 업데이트를 통해 다음 미리 보기 릴리스에 맞춰 자동으로 업그레이드됩니다.
+
+</p>
+
+<h3 id="revertDevice">기기를 공장 사양으로 되돌리기</h3>
+
+<p>
+  미리 보기의 설치를 제거하고 기기를 공장 사양으로 되돌리고자 하는 경우, <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a>를 방문하여 기기에 플래시하고자 하는 이미지를 다운로드하십시오.
+
+ 해당 페이지에 있는 지침을 따라 기기에 이미지를 플래시하면 됩니다.
+
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/ko/preview/index.jd b/docs/html-intl/intl/ko/preview/index.jd
index 9d0e040..badb9f6 100644
--- a/docs/html-intl/intl/ko/preview/index.jd
+++ b/docs/html-intl/intl/ko/preview/index.jd
@@ -29,7 +29,7 @@
 </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html-intl/intl/pt-br/index.jd b/docs/html-intl/intl/pt-br/index.jd
index 24dd2fe..4d0a39e 100644
--- a/docs/html-intl/intl/pt-br/index.jd
+++ b/docs/html-intl/intl/pt-br/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">Prepare-se para a próxima versão do
         Android. Teste os aplicativos no Nexus 5, 6, 9 e Player.  </p>
 
@@ -31,7 +28,7 @@
           Comece!</a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
   </div>
diff --git a/docs/html-intl/intl/pt-br/preview/download.jd b/docs/html-intl/intl/pt-br/preview/download.jd
index 12ef194..80685f9 100644
--- a/docs/html-intl/intl/pt-br/preview/download.jd
+++ b/docs/html-intl/intl/pt-br/preview/download.jd
@@ -164,14 +164,15 @@
   <div id="qv">
     <h2>Neste documento</h2>
       <ol>
-        <li><a href="#sdk">Preview SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">Documentação do desenvolvedor</a></li>
         <li><a href="#images">Imagens do sistema de hardware</a></li>
       </ol>
 
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+		   <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -184,7 +185,7 @@
 </p>
 
 
-<h2 id="sdk">Preview SDK</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   O Preview SDK está disponível para download no <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>. Para obter mais informações
@@ -204,11 +205,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -241,34 +242,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/pt-br/preview/download_mp2.jd b/docs/html-intl/intl/pt-br/preview/download_mp2.jd
new file mode 100644
index 0000000..12ef194
--- /dev/null
+++ b/docs/html-intl/intl/pt-br/preview/download_mp2.jd
@@ -0,0 +1,360 @@
+page.title=Downloads
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">Antes de fazer o download ou instalar componentes do Android Preview
+ SDK, você deve concordar com os seguintes termos e condições.</p>
+
+    <h2 class="norule">Termos e condições</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+Este é o contrato de licença do Android SDK Preview (o “Contrato de Licença”).
+
+1. Introdução
+
+1.1 O Android SDK Preview (que este Contrato de licença chama de "Preview", incluindo especificamente os arquivos de sistema do Android, APIs integradas e arquivos da biblioteca Preview, se e quando estiverem disponíveis) é licenciado por meio da concordância com os termos deste contrato. O Contrato de licença forma um vínculo contratual legal entre o contratante e a Google em relação ao uso do Preview.
+
+1.2 "Android" se refere à pilha de software do Android para dispositivos, conforme disponibilizado no Projeto de código aberto do Android, localizado no URL a seguir: http://source.android.com/, atualizado periodicamente.
+
+1.3 "Google" refere-se à Google Inc, uma corporação de Delaware, com sede em 1600 Amphitheatre Parkway, Mountain View, CA 94043, Estados Unidos.
+
+2. Aceitação do Contrato de Licença
+
+2.1 A fim de usar o Preview, é necessário concordar com este Contrato de licença. O uso do Preview é proibido àqueles que não concordam com este Contrato de licença.
+
+2.2 Ao clicar em aceitar e/ou usar o Preview, você concorda com os termos do Contrato de licença
+
+2.3 É proibido o uso do Preview e a aceitação deste contrato pelo indivíduo que tenha impedimento legal sobre o recebimento do Preview sob as leis dos Estados Unidos ou de outros países, incluindo o país de residência ou no qual usa o Preview.
+
+2.4 Se for usar o Preview internamente na empresa ou organização, você deverá concordar com o vínculo com este contrato em nome do empregador ou de outra entidade e declarar e garantir que tem total autoridade legal para tanto. Se você não tem a autoridade necessária, não deve concordar com este contrato nem usar o Preview em nome do empregador ou de outra entidade.
+
+3. Licença do Preview da Google
+
+3.1 Sujeito aos termos do Contrato de licença, a Google confere uma licença limitada, revogável, livre de taxas, intransmissível, não sub-licenciável e não exclusiva para o uso apenas do Preview, pessoal ou internamente dentro da sua empresa ou organização, para fins de desenvolvimento de aplicativos executados na plataforma do Android.
+
+3.2 Você concorda que a Google ou terceiros detêm todos os direitos legais, títulos e interesses relativos ao Preview, incluindo quaisquer direitos de propriedade intelectual que subsistam no Preview. "Direitos de propriedade intelectual" se referem a todo e qualquer direito sob as leis de patentes, de direitos autorais, de segredo comercial, de marca registrada e todos os outros direitos de propriedade. A Google reserva todos os direitos não conferidos expressamente a você.
+
+3.3 O uso do Preview não é autorizado para qualquer finalidade não expressamente permitida por este Contrato de licença. Salvo na extensão exigida por licenças aplicáveis de terceiros, é proibido: (a) copiar (exceto para fins de cópia de segurança), modificar, adaptar, redistribuir, descompilar, fazer engenharia reversa, desmontar ou criar trabalhos derivados do Preview ou qualquer parte dele; ou (b) carregar qualquer parte do Preview em um aparelho celular ou outro dispositivo de hardware, exceto em computador pessoal, combinar qualquer parte do Preview com outros softwares ou distribuir qualquer software ou dispositivo que contenha uma parte do Preview.
+
+3.4 Você concorda que não tomará quaisquer medidas que possam causar ou resultar em fragmentação do Android, incluindo, sem limitar-se, a distribuição e a participação na criação ou na promoção, sob quaisquer formas, de um conjunto de desenvolvimento de software derivado do Preview.
+
+3.5 O uso, a reprodução e a distribuição de componentes do Preview licenciado sob licença de software de código aberto são regidos exclusivamente pelos termos daquela licença de software de código aberto, e não por este Contrato de licença. Você concorda em manter uma licença em bom estado para as licenças de software de código aberto sob todos os direitos concedidos e deter quaisquer ações que possam limitar, suspender ou romper tais direitos.
+
+3.6 Você concorda que a forma e a natureza do SDK que a Google fornece podem mudar sem aviso prévio e que as versões futuras do SDK podem ser incompatíveis com aplicativos desenvolvidos em versões anteriores do SDK. Você concorda que a Google pode cessar (permanente ou temporariamente) o fornecimento do Preview (ou quaisquer recursos dentro dele) a você ou a usuários em geral sob critério exclusivo da Google, sem aviso prévio.
+
+3.7 Nada neste Contrato de licença confere o direito de uso de quaisquer nomes comerciais, marcas comerciais, marcas de serviço, logomarcas, nomes de domínios e outros recursos de marcas especiais da Google.
+
+3.8 Você concorda que não removerá, ocultará nem alterará quaisquer observações de direitos de propriedade (incluindo observações de direitos autorais e de marcas registradas) que possam estar afixadas ou contidas no Preview.
+
+4. Uso do Preview por você
+
+4.1 A Google compreende que nada no Contrato de licença dá a ela direito, título nem interesse no usuário (ou em seus licenciadores), sob o presente Contrato de licença, no que tange ao desenvolvimento de aplicativos de software através do uso do Preview, incluindo quaisquer direitos de propriedade intelectual que subsistam nos referidos aplicativos.
+
+4.2 Você concorda em usar o Preview e desenvolver aplicativos somente para as finalidades permitidas por (a) este Contrato de licença e (b) quaisquer leis, normas, diretrizes geralmente aceitas ou orientações aplicáveis nas jurisdições relevantes (incluindo quaisquer leis acerca da exportação e da importação de dados ou softwares nos Estados Unidos ou em outros países relevantes).
+
+4.3 Você concorda que, se usar o Preview para o desenvolvimento de aplicativos, deverá proteger a privacidade e os direitos legais destes usuários. Se nomes de usuário, senhas ou outras informações de acesso ou informações pessoais forem fornecidos ao aplicativo, deve-se informá-los de que tais dados estarão disponíveis para o aplicativo, além de fornecer observações de privacidade e proteção legalmente adequadas a esses usuários. Se o aplicativo armazenar informações pessoais ou confidenciais fornecidas pelos usuários, deve fazê-lo com segurança. Se o usuário fornecer informações da conta do Google, o aplicativo poderá usar essas informações exclusivamente para acessar a conta da Google do usuário quando houver autorização para fazê-lo e para os fins limitados pela autorização.
+
+4.4 Você concorda que não se envolverá em qualquer atividade com o Preview, incluindo o desenvolvimento e a distribuição de um aplicativo que interfira, perturbe, danifique ou acesse, de modo não autorizado, servidores, redes ou outras propriedades ou serviços da Google ou qualquer outro terceiro.
+
+4.5 Você concorda que é exclusivamente responsável por (e que a Google não tem qualquer responsabilidade com você ou terceiro) quaisquer dados, conteúdo ou recursos que criar, transmitir ou exibir por meio do Android e/ou de aplicativos do Android e pelas consequências que suas ações (incluindo perda ou dano que a Google possa sofrer) podem gerar.
+
+4.6 Você concorda que é exclusivamente responsável por (e que a Google não tem qualquer responsabilidade com você ou terceiro) qualquer violação das obrigações exigidas neste Contrato de licença, qualquer contrato ou termos de serviço aplicáveis a terceiros, qualquer lei ou norma aplicável e pelas consequências (incluindo a perda ou dano que a Google ou qualquer terceiro possa sofrer) de quaisquer violações.
+
+4.7 O Preview está em desenvolvimento e o seu teste e feedback são uma parte importante deste processo. Ao usar o Preview, você está ciente de que a implementação de alguns recursos ainda estão em desenvolvimento e que não se deve confiar que o Preview tem a funcionalidade completa de uma versão estável. Você concorda em não distribuir nem enviar publicamente quaisquer aplicativos usando este Preview, pois ele não será mais suportado após o lançamento oficial do Android SDK.
+
+5. Suas credenciais de desenvolvedor
+
+5.1 Você é responsável pela manutenção da confidencialidade de quaisquer credenciais de desenvolvedor que possam ser emitidas pela Google ou escolhidas por você e será o único responsável por todos os aplicativos que forem desenvolvidos sob suas credenciais de desenvolvedor.
+
+6. Privacidade e informações
+
+6.1 A fim de inovar e aprimorar continuamente o Preview, a Google pode coletar certas estatísticas de uso do software, incluindo, sem limitar-se, um identificador exclusivo, endereço IP associado, número de versão do software e informações sobre quais ferramentas e/ou serviços no Preview estão sendo usados e como estão sendo usados. Antes de coletar quaisquer dessas informações, o Preview o notificará e buscará seu consentimento. Se você recusar, as informações não serão coletadas.
+
+6.2 Os dados coletados são examinados coletivamente para aprimorar o Preview e são mantidos em conformidade com a Política de privacidade da Google acessível em http://www.google.com/policies/privacy/.
+
+7. Aplicativos de terceiros
+
+7.1 Ao usar o Preview para executar aplicativos desenvolvidos por terceiros ou que acessam dados, conteúdo ou recursos fornecidos por terceiros, você concorda que a Google não é responsável por tais aplicativos, dados, conteúdo ou recursos. Você compreende que quaisquer dados, conteúdo ou recursos passíveis de aceitação por meio de tais aplicativos de terceiros imputam responsabilidade exclusiva ao indivíduo que os originou. A Google não é responsável por qualquer perda ou dano que possa ocorrer como resultado do uso ou acesso de quaisquer aplicativos, dados, conteúdo ou recursos de terceiros.
+
+7.2 Você deve estar ciente de que os dados, conteúdo e recursos apresentados a você por aplicativos de terceiros podem ser protegidos pelos direitos de propriedade intelectual de posse dos fornecedores (ou de outras pessoas ou empresas em seus nomes). Não é permitido modificar, alugar, arrendar, emprestar, vender, distribuir nem criar trabalhos derivados com base nestes dados, conteúdo ou recursos (na totalidade ou em parte), salvo se houver permissão explícita especificada pelos respectivos detentores de direitos.
+
+7.3 Você reconhece que o uso de tais aplicativos, dados, conteúdo ou recursos de terceiros pode estar sujeito a termos adicionais entre você e o terceiro em questão.
+
+8. Uso de APIs da Google
+
+8.1 APIs da Google
+
+8.1.1 Ao usar qualquer API para recuperar dados da Google, você reconhece que eles podem ser protegidos por direitos de propriedade intelectual de posse da Google ou dos terceiros que fornecem os dados (ou de pessoas ou empresas em nomes deles). O uso de tal API pode estar sujeito a termos de serviço adicionais. Não é permitido modificar, alugar, arrendar, emprestar, vender, distribuir nem criar trabalhos derivados baseados nesses dados (na totalidade ou em parte), salvo se permitido pelos termos de serviço pertinentes.
+
+8.1.2 Se você usar qualquer API para recuperar dados de um usuário a partir da Google, reconhece e concorda que deve recuperar dados somente com consentimento explícito do usuário e somente quando, e para os fins limitados aos quais, o usuário conceder permissão para fazê-lo.
+
+9. Rescisão do Contrato de licença
+
+9.1 O Contrato de licença continuará a se aplicar até que ocorra uma rescisão sua ou da Google, como definido abaixo.
+
+9.2 Caso queira rescindir o Contrato de licença, você pode fazer isto cessando o uso do Preview e de qualquer credencial de desenvolvedor relevante.
+
+9.3 A Google pode, a qualquer momento, rescindir o Contrato de licença, com ou sem causa, com uma notificação.
+
+9.4 O Contrato de licença será encerrado automaticamente sem aviso ou outras ações na ocorrência de:
+(A) a Google interromper o fornecimento do Preview ou de determinadas partes do Preview aos usuários no país em que você reside ou de onde o serviço é usado; e
+(B) a Google emitir uma versão de lançamento final do Android SDK.
+
+9.5 Quando o Contrato de licença é rescindido, a licença concedida a você no Contrato de licença é finalizada, todo o uso do Preview será interrompido e as provisões dos parágrafos 10, 11, 12 e 14 deverão permanecer indefinidamente.
+
+10. EXCLUSÕES
+
+10.1 VOCÊ COMPREENDE E CONCORDA EXPRESSAMENTE QUE O RISCO DO USO DO PREVIEW É EXCLUSIVAMENTE SEU E QUE O PREVIEW É FORNECIDO NA FORMA EM QUE SE ENCONTRA E COMO DISPONIBILIZADO, SEM GARANTIA DE QUALQUER TIPO DA GOOGLE.
+
+10.2 O USO DO PREVIEW E DE QUALQUER MATERIAL BAIXADO OU OBTIDO DE OUTRO MODO PELO USO DO PREVIEW ESTÁ A SEU CRITÉRIO E RISCO E VOCÊ É O ÚNICO RESPONSÁVEL POR QUALQUER DANO AO SEU SISTEMA OPERACIONAL OU OUTRO DISPOSITIVO OU PELA PERDA DE DADOS QUE RESULTEM DE TAL USO. SEM LIMITAR OS PRECEDENTES, VOCÊ ENTENDE QUE O PREVIEW NÃO É UMA VERSÃO ESTÁVEL E QUE PODE CONTER ERROS, DEFEITOS E VULNERABILIDADES DE SEGURANÇA QUE PODEM RESULTAR EM DANOS SIGNIFICANTES, INCLUINDO A PERDA IRRECUPERÁVEL OU COMPLETA DO USO DO SISTEMA DO COMPUTADOR OU DE OUTROS DISPOSITIVOS.
+
+10.3 A GOOGLE EXCLUI EXPRESSAMENTE TODAS AS GARANTIAS E CONDIÇOES DE QUALQUER TIPO, EXPRESSAS OU IMPLÍCITAS, INCLUINDO, MAS NÃO LIMITADO A, GARANTIAS E CONDIÇÕES DE COMERCIALIZAÇÃO IMPLÍCITAS, ADEQUAÇÃO A UMA FINALIDADE PARTICULAR E A NÃO VIOLAÇÃO.
+
+11. LIMITAÇÃO DE RESPONSABILIDADE
+
+11.1 VOCÊ COMPREENDE E CONCORDA EXPRESSAMENTE QUE A GOOGLE, SUAS SUBSIDIÁRIAS, AFILIADAS E SEUS LICENCIADORES NÃO SERÃO RESPONSABILIZADOS POR VOCÊ SOB QUALQUER TEORIA DE RESPONSABILIDADE POR QUAISQUER DANOS, SEJAM ELES DIRETOS, INDIRETOS, INCIDENTAIS, ESPECIAIS, CONSEQUENCIAIS OU DE EXEMPLO QUE POSSAM INCORRER, INCLUINDO QUALQUER PERDA DE DADOS, INDEPENDENTE DE AVISO À GOOGLE OU A SEUS REPRESENTANTES OU DA NECESSIDADE DE AVISO SOBRE A POSSIBILIDADE DA INCORRÊNCIA DE TAIS PERDAS.
+
+12. Indenização
+
+12.1 Ao limite máximo permitido por lei, você concorda em defender, indenizar e isentar a Google, suas afiliadas e respectivos conselheiros, diretores, empregados e agentes com relação a todas e quaisquer reivindicações, ações, processos ou procedimentos, bem como todas e quaisquer perdas, responsabilidades, danos, custos e despesas (incluindo honorários advocatícios) decorrentes ou provenientes de: (a) seu uso do Preview, (b) qualquer aplicativo desenvolvido no Preview que infrinja direitos de propriedade intelectual de qualquer pessoa, difame qualquer pessoa ou viole seus direitos de publicidade ou privacidade e (c) qualquer não cumprimento deste Contrato de licença.
+
+13. Mudanças no Contrato de licença
+
+13.1 A Google pode realizar mudanças no Contrato de licença à medida que distribui novas versões do Preview. Quando essas mudanças forem realizadas, a Google fará uma nova versão do Contrato de licença disponível no site em que o Preview estiver disponível.
+
+14. Termos legais gerais
+
+14.1 Esse Contrato de licença constitui o contrato legal integral entre você e a Google e rege o uso do Preview (excluindo quaisquer serviços que a Google possa fornecer a você sob um contrato escrito em separado), e substitui inteiramente quaisquer contratos anteriores entre você e a Google em relação ao Preview.
+
+14.2 Você concorda que, se a Google não exercer nem impetrar qualquer direito ou recurso legal que esteja contido no Contrato de licença (ou que a Google detenha direitos nos termos de qualquer lei aplicável), não se considerará esse fato como uma renúncia formal aos direitos da Google e esses direitos ou recursos continuarão disponíveis à Google.
+
+14.3 Se qualquer tribunal de justiça que tiver a competência para decidir sobre esse tema determinar que qualquer cláusula do Contrato de licença é inválida, tal cláusula será removida do contrato sem afetar as cláusulas restantes ou sua vigência. As cláusulas restantes do Contrato de licença continuarão válidas e obrigatórias.
+
+14.4 Você reconhece e concorda que cada membro do grupo de empresas das quais a Google é a empresa controladora deve ser beneficiário terceiro do Contrato de licença e que essas outras empresas terão o poder de aplicar diretamente, e apoiar-se em, qualquer cláusula do Contrato de licença que confira um direito (ou direitos em favor) deles. Além disso, nenhuma outra pessoa nem empresa deve ser beneficiário terceiro do Contrato de licença.
+
+14.5 RESTRIÇÕES DE EXPORTAÇÃO. O PREVIEW ESTÁ SUJEITO ÀS LEIS E NORMAS DE EXPORTAÇÃO DOS ESTADOS UNIDOS. VOCÊ DEVE CUMPRIR TODAS AS LEIS E NORMAS DOMÉSTICAS E INTERNACIONAIS QUE SE APLICAREM AO PREVIEW. ESSAS LEIS INCLUEM RESTRIÇÕES SOBRE DESTINOS, USUÁRIOS FINAIS E USO FINAL.
+
+14.6 O Contrato de licença não pode ser atribuído nem transferido por você sem a aprovação prévia por escrito da Google. Qualquer tentativa de atribuição sem a aprovação será inválida. Você não deve delegar as próprias responsabilidades ou obrigações nos termos do Contrato de licença sem aprovação prévia por escrito da Google.
+
+14.7 O Contrato de licença e sua relação com a Google nos termos do contrato serão regidos pelas leis do estado da Califórnia sem considerar conflitos de disposições legais. Você e a Google concordam em se submeter à competência exclusiva dos tribunais localizados na comarca de Santa Clara, Califórnia, para dirimir quaisquer questões legais decorrentes do Contrato de licença. Não obstante a isso, você concorda que a Google continua habilitada a impetrar medidas cautelares (ou mecanismo legal urgente equivalente) em qualquer jurisdição.
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">Li e concordo com todos os termos e condições expressos acima</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>Neste documento</h2>
+      <ol>
+        <li><a href="#sdk">Preview SDK</a></li>
+        <li><a href="#docs">Documentação do desenvolvedor</a></li>
+        <li><a href="#images">Imagens do sistema de hardware</a></li>
+      </ol>
+
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  O Android M Preview SDK inclui ferramentas de desenvolvimento, arquivos de sistema do Android e arquivos da biblioteca
+ para ajudar você a testar o aplicativo e novas APIs da próxima versão da plataforma. Este documento
+ descreve como adquirir os componentes disponíveis para download da prévia para o teste do aplicativo.
+</p>
+
+
+<h2 id="sdk">Preview SDK</h2>
+
+<p>
+  O Preview SDK está disponível para download no <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK Manager</a>. Para obter mais informações
+ sobre o download e a configuração do Preview SDK, consulte <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Configuração do Preview SDK</a>.
+</p>
+
+
+<h2 id="docs">Documentação do desenvolvedor</h2>
+
+<p>
+  O pacote de download da documentação do desenvolvedor fornece informações de referência de API detalhadas e um relatório de diferença de API para a prévia.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">Imagens do sistema de hardware</h2>
+
+<p>
+  Essas imagens do sistema permitem que você instale uma versão de prévia da plataforma em um dispositivo físico
+para fins de teste. Ao configurar um dispositivo com uma dessas imagens, é possível instalar e testar o aplicativo
+ para verificar o seu desempenho na próxima versão da plataforma. O processo de instalação de uma imagem do sistema
+ em um dispositivo <em>remove todos os dados do dispositivo</em>. Portanto, deve-se realizar um backup dos dados
+ antes de instalar uma imagem do sistema.
+</p>
+
+<p class="warning">
+  <b>Aviso:</b> as seguintes imagens do sistema Android são prévias e estão sujeitas a alterações. O uso
+ dessas imagens do sistema são governadas pelo Contrato de licença do Android SDK Preview. As imagens do sistema do Android Preview
+ não são versões estáveis e podem conter erros e defeitos que podem resultar
+ em danos aos sistemas do computador, aos dispositivos e aos dados. As imagens do sistema Android Preview
+ não estão sujeitas ao mesmo teste do sistema operacional de fábrica e podem fazer com que o telefone e aplicativos e os serviços
+ instalados parem de funcionar.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">Instalar uma imagem no dispositivo</h3>
+
+<p>
+  Para usar uma imagem de dispositivo para testes, deve-se instalá-lo em um dispositivo compatível. Siga
+ as instruções abaixo para instalar uma imagem de sistema.
+</p>
+
+<ol>
+  <li>Faça o download e descompacte um dos pacotes de imagem do sistema listados aqui.</li>
+  <li>Faça um backup dos dados do dispositivo que deseja preservar.</li>
+  <li>Siga as instruções em
+ <a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+  para programar em flash a imagem no dispositivo.</li>
+</ol>
+
+<p class="note">
+  <strong>Observação:</strong> ao programar em flash a imagem do sistema de prévia no dispositivo de desenvolvimento,
+ ele é atualizado automaticamente com o próximo lançamento da prévia por meio de atualizações over-the-air (OTA).
+</p>
+
+<h3 id="revertDevice">Reverter um dispositivo para as especificações de fábrica</h3>
+
+<p>
+  Caso queira desinstalar a prévia e reverter o dispositivo para as especificações de fábrica, acesse
+ <a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> e
+ faça o download da imagem que deseja programar em flash no dispositivo. Siga as instruções nesta página
+ para programar em flash a imagem no dispositivo.
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/pt-br/preview/index.jd b/docs/html-intl/intl/pt-br/preview/index.jd
index 172b211..6936718 100644
--- a/docs/html-intl/intl/pt-br/preview/index.jd
+++ b/docs/html-intl/intl/pt-br/preview/index.jd
@@ -29,7 +29,7 @@
 </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html-intl/intl/ru/index.jd b/docs/html-intl/intl/ru/index.jd
index 3fe65ea..3da0b9e 100644
--- a/docs/html-intl/intl/ru/index.jd
+++ b/docs/html-intl/intl/ru/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">Подготовьтесь к выходу следующей версии
         платформы Android. Протестируйте ваши приложения на устройствах Nexus
         5, 6, 9 и Player. </p>
@@ -33,7 +30,7 @@
         </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
   </div>
diff --git a/docs/html-intl/intl/ru/preview/download.jd b/docs/html-intl/intl/ru/preview/download.jd
index 13872d1..9afc62b 100644
--- a/docs/html-intl/intl/ru/preview/download.jd
+++ b/docs/html-intl/intl/ru/preview/download.jd
@@ -164,13 +164,14 @@
   <div id="qv">
     <h2>Содержание документа</h2>
       <ol>
-        <li><a href="#sdk">SDK Preview</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">Документация для разработчиков</a></li>
         <li><a href="#images">Системные образы оборудования</a></li>
       </ol>
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+		   <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -183,7 +184,7 @@
 </p>
 
 
-<h2 id="sdk">SDK Preview</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   Загрузить SDK Preview можно с помощью <a href="{@docRoot}tools/help/sdk-manager.html">менеджера SDK Android</a>. Дополнительные сведения
@@ -203,11 +204,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -240,34 +241,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
       </td>
   </tr>
 
diff --git a/docs/html-intl/intl/ru/preview/download_mp2.jd b/docs/html-intl/intl/ru/preview/download_mp2.jd
new file mode 100644
index 0000000..13872d1
--- /dev/null
+++ b/docs/html-intl/intl/ru/preview/download_mp2.jd
@@ -0,0 +1,359 @@
+page.title=Загрузки
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">Прежде чем приступить к загрузке и установке компонентов пакета SDK Android Preview,
+примите следующие положения и условия.</p>
+
+    <h2 class="norule">Положения и условия</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+Это лицензионное соглашение для пакета SDK Android Preview (далее «Лицензионное соглашение»).
+
+1. Введение
+
+1.1. Лицензия на пакет SDK Android Preview (далее по тексту настоящего Лицензионного соглашения – «Preview», который включает системные файлы Android, пакеты API-интерфейсов и файлы библиотеки Preview, если такие доступны) передается в соответствии с положениями настоящего Лицензионного соглашения. Настоящее Лицензионное соглашение является юридически обязывающим договором между компанией Google и любым лицом, использующим Preview.
+
+1.2. В настоящем Лицензионном соглашении термин «Android» означает набор программного обеспечения Android для устройств, предлагаемый к использованию в рамках проекта Android Open Source Project, который доступен на веб-сайте http://source.android.com/ (сведения, размещенные на этом сайте, могут периодически обновляться).
+
+1.3. Под термином «Google» понимается корпорация Google Inc., главный офис которой находится по адресу 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States (США).
+
+2. Принятие лицензионного соглашения
+
+2.1. Использование Preview возможно только после принятия условий настоящего Лицензионного соглашения. Запрещается использовать Preview, если вы не согласны с указанными в настоящем документе условиями и положениями.
+
+2.2. Нажатие кнопки принятия условий и/или использование Preview означает, что вы согласны с положениями настоящего Лицензионного соглашения.
+
+2.3. Вы не вправе использовать Preview и принимать условия данного Лицензионного соглашения, если по законам США или иных стран, включая страну вашего проживания или использования Preview, запрещается передавать Preview в ваш адрес.
+
+2.4. Если вы используете Preview в рамках своей компании или организации, вы соглашаетесь взять на себя обязательства по соблюдению настоящего Лицензионного соглашения от имени своего работодателя или другого юридического лица, и вы тем самым подтверждаете и гарантируете, что обладаете полными юридическими полномочиями связать вашего работодателя или иное подобное юридическое лицо обязательствами по настоящему Лицензионному соглашению. Если вы не обладаете необходимыми полномочиями, вы не вправе принимать указанные в настоящем документе условия и положения или использовать Preview от имени вашего работодателя или другого юридического лица.
+
+3. Лицензия на Preview от Google
+
+3.1. В соответствии с условиями настоящего Лицензионного соглашения Google предоставляет вам ограниченную, бесплатную и неэксклюзивную лицензию без права передачи и подлежащую отмене, на использование Preview, лично или в рамках своей компании или организации, исключительно в целях разработки приложений для платформы Android.
+
+3.2. Вы соглашаетесь с тем, что Google или третьим сторонам принадлежат все юридические и имущественные права, а также правовой интерес в отношении Preview, в том числе любые права на объекты интеллектуальной собственности, которые имеются в Preview. Термин «Права на интеллектуальную собственность» означает все возможные права в рамках патентного права, авторского права, закона о коммерческой тайне, закона о товарных знаках, а также иные возможные имущественные права. Google оставляет за собой все права, не предоставленные вам в явном виде.
+
+3.3. Вам запрещается использовать Preview в любых целях, которые однозначно не определены в настоящем Лицензионном соглашении. За исключением случаев, предусмотренных применимыми сторонними лицензиями, вам запрещается: (a) копировать (кроме случаев резервного копирования), изменять, адаптировать, повторно распространять, декомпилировать, осуществлять инженерный анализ, деассемблировать или создавать производные элементы Preview или иной его части; а также (b) загружать любую часть Preview в мобильные телефоны или иные устройства, помимо персонального компьютера, объединять любые части Preview с другим программным обеспечением, распространять любое программное обеспечение или устройства, содержащие части Preview.
+
+3.4. Вы соглашаетесь с тем, что не будете предпринимать никаких действий, которые прямо или косвенно могут привести к фрагментированию платформы Android, включая помимо прочего распространение набора средств разработки программного обеспечения, полученного из Preview, участие в создании таких средств и содействие их продвижению в любой форме.
+
+3.5. Использование, воспроизведение и распространение компонентов Preview, на которые распространяется лицензия на программное обеспечение с открытым исходным кодом, регулируются исключительно положениями и условиями такой лицензии на программное обеспечение с открытым исходным кодом, а не настоящим Лицензионным соглашением. Вы соглашаетесь обеспечивать хорошую репутацию получателя лицензии в отношении таких лицензии на программное обеспечение с открытым исходным кодом в рамках всех предоставленных ему прав, а также не допускать каких-либо действий, которые могут привести к аннулированию, приостановлению или нарушению таких прав
+
+3.6. Вы соглашаетесь с тем, что форма и содержание Preview , предоставляемого Google, могут быть изменены без предварительного уведомления, а также с тем, что будущие версии Preview могут оказаться несовместимыми с приложениями, разработанными в предыдущих версиях Preview. Вы соглашаетесь с тем, что Google вправе по собственному усмотрению и без предварительного уведомления прекратить (временно или навсегда) предоставление Preview (или любых функций в составе Preview) вам или пользователям.
+
+3.7. Ни одна из частей настоящего Лицензионного соглашения не предусматривает предоставления вам права использовать любые торговые наименования, товарные знаки, знаки обслуживания, логотипы, имена доменов или иные отличительные фирменные знаки, принадлежащие Google.
+
+3.8. Вы соглашаетесь с тем, что обязуетесь не удалять, не скрывать или не изменять любые уведомления об имущественных правах (включая уведомления об авторских правах и товарных знаках), которые могут сопровождать Preview или содержаться в нем.
+
+4. Использование Preview
+
+4.1. Компания Google выражает согласие с тем, что ни по какому положению настоящего Лицензионного соглашения не получает от вас (или ваших лицензиаров) каких-либо юридических и имущественных прав, а также правового интереса в отношении любых программных приложений, разработанных вами с помощью Preview, включая любые права на объекты интеллектуальной собственности, которые имеются в таких приложениях.
+
+4.2. Вы соглашаетесь использовать Preview и создавать приложения исключительно в целях, предусмотренных (a) настоящим Лицензионным соглашением и (b) любым применимым законом, нормативным актом или общепринятыми правилами или рекомендациями в соответствующей юрисдикции (включая любые законы, касающиеся экспорта данных или программного обеспечения из США или иных соответствующих стран, а также импорта в них).
+
+4.3. Вы соглашаетесь с тем, что при использовании Preview для разработки приложений вы обязуетесь обеспечивать конфиденциальность и защищать юридические права пользователей. В случае, если пользователи предоставляют вам свои имена, пароли или иные данные для входа либо свои персональные данные, вы обязуетесь уведомить пользователей о том, что такая информация будет присутствовать в вашем приложении, и вы также обязуетесь предоставить пользователям юридически соответствующие уведомление о конфиденциальности и средства правовой защиты. Если в вашем приложении хранится личная или конфиденциальная информация, предоставленная пользователями, вы обязуетесь обеспечить ее надлежащую защиту. Если пользователь предоставляет вам сведения о своей учетной записи Google, то ваше приложение может использовать такую информацию для доступа к учетной записи Google пользователя только при условии, что пользователь предоставил вам разрешение на это, и только в тех целях, которые обозначил пользователь.
+
+4.4. Вы соглашаетесь с тем, что обязуетесь не использовать Preview для любого рода деятельности, в том числе для разработки или распространения приложений, в целях нарушения работы и повреждения серверов, сетей или иной собственности или служб Google или любой третьей стороны.
+
+4.5. Вы соглашаетесь с тем, что несете единоличную ответственность (и признаете, что компания Google не несет ответственности ни перед вами, ни перед любой третьей стороной) за любые данные, содержимое или ресурсы, которые вы создаете, передаете или демонстрируете посредством Android и/или приложений для Android, а также за любые последствия ваших действий, связанных с этим (в том числе за любые убытки и любой ущерб, которые могут быть причинены Google).
+
+4.6. Вы соглашаетесь с тем, что несете единоличную ответственность (и признаете, что компания Google не несет ответственности ни перед вами, ни перед любой третьей стороной) за любое несоблюдение обязательств по настоящему Лицензионному соглашению, обязательств по любому применимому договору с третьей стороной или предусмотренных Условиями и положениями, за нарушение любых применимых законов или нормативных актов, а также за любые последствия ваших действий, связанных с таким нарушением (в том числе за любые убытки и любой ущерб, которые могут быть причинены Google).
+
+4.7 Preview находится на стадии разработки, поэтому ваши отзывы и результаты тестирования являются важной частью процесса разработки. Используя Preview, вы признаете, что реализация некоторых функций по-прежнему находится на этапе разработки и вам не следует рассчитывать на полную функциональность стабильной версии. Вы соглашаетесь не распространять или предоставлять любые приложения, использующие Preview, поскольку поддержка Preview будет прекращена после выпуска официальной версии пакета SDK Android.
+
+5. Ваши учетные данные разработчика
+
+5.1. Вы соглашаетесь с тем, что несете ответственность за обеспечение конфиденциальности любых учетных данных разработчика, которые компания Google может вам предоставить или которые вы можете самостоятельно выбрать, а также с тем, что вы несете единоличную ответственность за все приложения, разработанные с использованием ваших учетных данных разработчика.
+
+6. Конфиденциальность и личная информация
+
+6.1. В целях постоянного совершенствования и улучшения Preview компания Google вправе собирать определенные статистические данные об использовании программного обеспечения, включая уникальный идентификатор, связанный IP-адрес, номер версии программного обеспечения, а также сведения об используемых в Preview инструментах и/или службах и способах их применения. Перед тем как любые из таких данных будут отправлены в Google, в Preview отобразится соответствующее уведомление с просьбой дать свое согласие. В случае вашего отказа предоставить такие сведения соответствующие данные собираться не будут.
+
+6.2. Собранные данные изучаются в обобщенном виде с целью улучшения Preview и хранятся в соответствии с Политикой конфиденциальности Google, которая опубликована на веб-сайте по адресу http://www.google.com/policies/privacy/.
+
+7. Сторонние приложения
+
+7.1. Если вы используете Preview для запуска приложений, разработанных третьими сторонами или получающих доступ к данным, содержимому или ресурсам, предоставляемым третьей стороной, вы соглашаетесь с тем, что Google не несет ответственности за такие приложения, данные, содержимое или ресурсы. Вы осознаете, что единоличную ответственность за все данные, содержимое или ресурсы, доступ к которым вы можете получить посредством таких приложений третьих сторон, несет лицо, предоставившее их, а также то, что Google не несет ответственности за любые убытки или любой ущерб, которые могут возникнуть в результате использования вами любых таких сторонних приложений, данных, содержимого или ресурсов и в результате обращения к ним.
+
+7.2. Вы должны быть осведомлены о том, что данные, содержимое и ресурсы, предоставляемые вам посредством таких сторонних приложений, могут быть защищены правами на объекты интеллектуальной собственности, принадлежащие предоставляющим их лицам (или иным лицам либо компаниям от их имени). Вам запрещается изменять, сдавать в аренду, передавать, продавать, распространять такие данные, содержимое или ресурсы (полностью или частично), а также создавать на их основе производные элементы, если у вас нет на это разрешения от соответствующих владельцев.
+
+7.3. Вы осознаете, что использование вами таких сторонних приложений, данных или ресурсов может регулироваться отдельными условиями, заключенными между вами и соответствующей третьей стороной.
+
+8. Использование API-интерфейсов Google
+
+8.1. API-интерфейсы для получения данных Google.
+
+8.1.1. В случае использования вами любых API для получения данных из Google вы осознаете, что такие данные могут быть защищены правами на объекты интеллектуальной собственности, принадлежащие Google или предоставляющим их сторонам (или иным лицам либо компаниям от их имени). Использование вами подобных API может регулироваться дополнительными Условиями использования. Вам запрещается изменять, сдавать в аренду, передавать, продавать, распространять такие данные (полностью или частично), а также создавать на их основе производные элементы, если это не разрешено соответствующими Условиями использования.
+
+8.1.2. Если вы используете какие-либо API-интерфейсы для получения данных пользователя из Google, вы осознаете и соглашаетесь с тем, что вы обязуетесь получать такие данные исключительно с прямого согласия пользователя и только в тех целях, которые обозначил пользователь.
+
+9. Прекращение действия Лицензионного соглашения
+
+9.1 Настоящее Лицензионное соглашение остается в силе до тех пор, пока его действие не будет прекращено вами или Google, как указано ниже.
+
+9.2. Если вы желаете прекратить действие настоящего Лицензионного соглашения, вы вправе сделать это, прекратив использование Preview и любых соответствующих учетных данных разработчика.
+
+9.3. Google вправе в любое время прекратить действие настоящего Лицензионного соглашения, отправив предварительное уведомление или без него.
+
+9.4 Действие настоящего Лицензионного соглашения автоматически прекращается без предварительного уведомления или выполнения иных действий сразу после любого из следующих событий:
+(A) компания Google прекращает предоставление Preview или определенных частей Preview пользователям на территории страны, в которой вы проживаете или используете услуги компании;
+(B) компания Google выпускает окончательную версию SDK Android.
+
+9.5 В случае прекращения действия настоящего Лицензионного соглашения прекращается действие лицензии, предоставленной в рамках Лицензионного соглашения, и вам следует незамедлительно прекратить любое использование Preview, тогда как положения, изложенные в разделах 10, 11, 12 и 14 продолжают действовать бессрочно.
+
+10. ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ
+
+10.1. ВЫ ЧЕТКО ОСОЗНАЕТЕ И БЕЗОГОВОРОЧНО СОГЛАШАЕТЕСЬ С ТЕМ, ЧТО ВЫ ИСПОЛЬЗУЕТЕ PREVIEW ИСКЛЮЧИТЕЛЬНО НА СВОЙ СТРАХ И РИСК И ЧТО PREVIEW ПРЕДОСТАВЛЯЕТСЯ ВАМ НА УСЛОВИЯХ «КАК ЕСТЬ» И «КАК ДОСТУПНО» БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ СО СТОРОНЫ КОМПАНИИ GOOGLE.
+
+10.2 ИСПОЛЬЗОВАНИЕ ВАМИ PREVIEW И ЗАГРУЗКА ЛЮБЫХ МАТЕРИАЛОВ И ИХ ПОЛУЧЕНИЕ ИНЫМ СПОСОБОМ С ПОМОЩЬЮ PREVIEW ВЫПОЛНЯЕТСЯ ПО ВАШЕМУ СОБСТВЕННОМУ УСМОТРЕНИЮ НА СВОЙ СТРАХ И РИСК. ВСЯ ОТВЕТСТВЕННОСТЬ ЗА ЛЮБОЙ УЩЕРБ, ПРИЧИНЕННЫЙ ВАШЕЙ ВЫЧИСЛИТЕЛЬНОЙ СИСТЕМЕ ИЛИ ДРУГОМУ ОБОРУДОВАНИЮ, А ТАКЖЕ ЗА ПОТЕРЮ ДАННЫХ, ВЫЗВАННУЮ ПОДОБНЫМ ИСПОЛЬЗОВАНИЕМ, ВОЗЛАГАЕТСЯ НА ВАС. НЕ ОГРАНИЧИВАЯ ВЫШЕСКАЗАННОЕ, ВЫ ПОНИМАЕТЕ, ЧТО PREVIEW НЕ ЯВЛЯЕТСЯ СТАБИЛЬНЫМ ВЫПУСКОМ И МОЖЕТ СОДЕРЖАТЬ ОШИБКИ, ДЕФЕКТЫ И УЯЗВИМОСТИ В СИСТЕМЕ БЕЗОПАСНОСТИ, КОТОРЫЕ МОГУТ ПРИВЕСТИ К СЕРЬЕЗНЫМ ПОВРЕЖДЕНИЯМ, ВКЛЮЧАЯ ПОЛНУЮ И БЕЗВОЗВРАТНУЮ ПОТЕРЮ РАБОТОСПОСОБНОСТИ ВАШЕГО КОМПЬЮТЕРА ИЛИ ИНОГО УСТРОЙСТВА.
+
+10.3. КОМПАНИЯ GOOGLE БЕЗОГОВОРОЧНО ОТКАЗЫВАЕТСЯ ОТ ЯВНЫХ И НЕЯВНЫХ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, ВКЛЮЧАЯ ПОМИМО ПРОЧЕГО НЕЯВНЫЕ ГАРАНТИИ И УСЛОВИЯ ТОВАРНОГО СОСТОЯНИЯ, ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННОЙ ЦЕЛИ И ОТСУТСТВИЯ НАРУШЕНИЙ ПРАВ СОБСТВЕННОСТИ.
+
+11. ОГРАНИЧЕНИЕ ОТВЕТСТВЕННОСТИ
+
+11.1. ВЫ ЧЕТКО ОСОЗНАЕТЕ И БЕЗОГОВОРОЧНО СОГЛАШАЕТЕСЬ С ТЕМ, ЧТО КОМПАНИЯ GOOGLE, ЕЕ ДОЧЕРНИЕ И АФФИЛИРОВАННЫЕ КОМПАНИИ И ЛИЦЕНЗИАРЫ НЕ НЕСУТ ПЕРЕД ВАМИ ОТВЕТСТВЕННОСТИ, НЕЗАВИСИМО ОТ ЕЕ ПРИЧИНЫ И ВИДА, ЗА КАКИЕ-ЛИБО ПРЯМЫЕ, КОСВЕННЫЕ, СЛУЧАЙНЫЕ, СПЕЦИАЛЬНЫЕ, ОПОСРЕДОВАННЫЕ И ШТРАФНЫЕ УБЫТКИ, ПОНЕСЕННЫЕ ВАМИ, ВКЛЮЧАЯ ПОТЕРЮ ДАННЫХ, ВНЕ ЗАВИСИМОСТИ ОТ ТОГО, БЫЛА ЛИ КОМПАНИЯ GOOGLE ИЛИ ЕЕ ПРЕДСТАВИТЕЛИ ИЗВЕЩЕНЫ О ВОЗМОЖНОСТИ ТАКОГО УЩЕРБА.
+
+12 Освобождение от ответственности
+
+12.1. В максимально допустимой законом степени вы соглашаетесь защищать, освобождать от ответственности и возможных претензий компанию Google, ее аффилированные компании и их соответствующих руководителей, служащих, сотрудников и агентов от всех возможных правовых требований, действий, судебных исков или разбирательств, а также от всех возможных убытков, обязательств, ущерба, издержек и расходов (включая обоснованные вознаграждения для адвокатов), возникающих в связи (a) с использованием вами Preview, (b) любыми приложениями, разрабатываемыми вами с помощью Preview и нарушающими любые права на объекты интеллектуальной собственности любого лица, а также порочащие любое лицо либо нарушающие права таких лиц на публичность и конфиденциальность, а также (c) в связи с любым несоблюдением вами положений настоящего Лицензионного соглашения.
+
+13. Изменения в Лицензионном соглашении
+
+13.1. Компания Google вправе вносить изменения в настоящее Лицензионное соглашение по мере выхода новых версий Preview. При внесении изменений Google создает новую версию Лицензионного соглашения и размещает ее на веб-сайте, на котором размещен Preview.
+
+14. Общие правовые условия
+
+14.1. Настоящее Лицензионное соглашение составляет полный текст юридического соглашения между вами и компанией Google, регулирует использование вами Preview (за исключением услуг, которые Google предоставляет на основании отдельного письменного соглашения) и полностью заменяет собой все предыдущие соглашения между вами и компанией Google в отношении Preview.
+
+14.2. Вы соглашаетесь с тем, что отсутствие каких-либо действий или судебных исков со стороны Google, направленных на соблюдение каких-либо правовых норм или исполнение средств правовой защиты, установленных настоящим Лицензионным соглашением (или которыми Google обладает в соответствии с каким-либо действующим законом), не означает отказ компании Google от своих прав и не препятствует компании Google использовать эти права или средства защиты.
+
+14.3. Если какой-либо судебный орган, уполномоченный рассматривать этот вопрос, признает недействительность какого-либо положения данного Лицензионного соглашения, то соответствующее положение будет исключено из Лицензионного соглашения с сохранением действия всех остальных его положений. Остальные положения Лицензионного соглашения по-прежнему будут действовать, и их соблюдение может обеспечиваться в судебном порядке.
+
+14.4. Вы признаете и соглашаетесь с тем, что все участники группы компаний, среди которых Google является материнской компанией, являются сторонними бенефициарами Лицензионного соглашения и что эти компании имеют право пользоваться привилегиями (или правами), предоставляемыми по настоящему Лицензионному соглашению, и напрямую требовать их соблюдения в судебном порядке. Все остальные физические и юридические лица не являются сторонними бенефициарами Лицензионного соглашения.
+
+14.5. ОГРАНИЧЕНИЯ НА ЭКСПОРТ. ИСПОЛЬЗОВАНИЕ PREVIEW РЕГУЛИРУЕТСЯ ЗАКОНАМИ И НОРМАТИВНЫМИ АКТАМИ США, КАСАЮЩИМИСЯ ЭКСПОРТА. ВЫ ОБЯЗУЕТЕСЬ СОБЛЮДАТЬ ВСЕ НАЦИОНАЛЬНЫЕ И МЕЖДУНАРОДНЫЕ ЗАКОНЫ ОБ ЭКСПОРТЕ, ПРИМЕНИМЫЕ К PREVIEW. ДАННЫЕ ЗАКОНЫ НАЛАГАЮТ ОГРАНИЧЕНИЯ НА РЕГИОНЫ, КРУГ ЛИЦ И СПОСОБ КОНЕЧНОГО ИСПОЛЬЗОВАНИЯ.
+
+14.6. Вы не вправе переуступать либо передавать права, предоставляемые по настоящему Лицензионному соглашению, без предварительного письменного согласия Google; любые попытки переуступки без такого согласия считаются недействительными. Вы обязуетесь не делегировать свои полномочия или обязательства по настоящему Лицензионному соглашению без предварительного письменного согласия Google.
+
+14.7. Лицензионное соглашение, а также взаимоотношения между вами и компанией Google в рамках настоящего Лицензионного соглашения регулируются законодательством штата Калифорния за исключением его норм коллизионного права. Вы и компания Google признаете, что урегулирование любых правовых вопросов, связанных с данным Лицензионным соглашением, относится исключительно к юрисдикции судов округа Санта-Клара, штат Калифорния. Несмотря на это, вы соглашаетесь с тем, что компания Google по-прежнему имеет право обращаться за наложением судебного запрета (или за получением аналогичного вида неотложной судебной защиты) в суды любой юрисдикции.
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">Я прочитал(а) и принимаю изложенные выше положения и условия</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>Содержание документа</h2>
+      <ol>
+        <li><a href="#sdk">SDK Preview</a></li>
+        <li><a href="#docs">Документация для разработчиков</a></li>
+        <li><a href="#images">Системные образы оборудования</a></li>
+      </ol>
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  В состав SDK Android M Preview входят инструменты для разработки, системные файлы Android и файлы библиотеки, призванные
+помочь вам в тестировании ваших приложений и новых API-интерфейсов, которые будут реализованы в предстоящем выпуске платформы. В этом документе
+рассказывается, как загрузить необходимые компоненты Preview для тестирования ваших приложений.
+</p>
+
+
+<h2 id="sdk">SDK Preview</h2>
+
+<p>
+  Загрузить SDK Preview можно с помощью <a href="{@docRoot}tools/help/sdk-manager.html">менеджера SDK Android</a>. Дополнительные сведения
+о загрузке и настройке SDK Preview представлены в статье <a href="{@docRoot}preview/setup-sdk.html#downloadSdk">Настройка SDK Preview</a>.
+</p>
+
+
+<h2 id="docs">Документация для разработчиков</h2>
+
+<p>
+  В пакете документации для разработчиков, который доступен для загрузки, представлены подробные сведения об API-интерфейсах, а также о различиях между API-интерфейсами для Preview.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">Системные образы оборудования</h2>
+
+<p>
+  С помощью этих системных образов можно установить предварительную версию платформы на физическое устройство для
+тестирования. Используя один из этих образов для настройки устройства, вы можете установить и протестировать ваше приложение, чтобы узнать, как оно будет работать в будущей версии
+платформы. В процессе установки системного образа
+<em>на устройстве удаляются все данные</em>, поэтому перед установкой образа обязательно сделайте резервное копирование данных.
+
+</p>
+
+<p class="warning">
+  <b>Предупреждение.</b> Перечисленные ниже системные образы Android являются предварительными и могут быть изменены. Использование вами
+этих образов регулируется Лицензионным соглашением на использование пакета SDK Android Preview. Системные образы предварительной версии Android
+не являются стабильными и могут содержать ошибки и дефекты,
+способные повредить ваши компьютеры, устройства и данные. Системные образы предварительной версии Android не проходят такое же тестирование,
+как заводская ОС. Поэтому в результате использования этих образов ваш телефон и установленные на нем приложения
+и службы могут перестать работать.
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">Установка образа на устройство</h3>
+
+<p>
+  Чтобы воспользоваться образом устройства для тестирования, установите его на совместимое устройство. Следуйте
+инструкциям по установке системного образа.
+</p>
+
+<ol>
+  <li>Загрузите и распакуйте один из указанных выше пакетов с системным образом.</li>
+  <li>Создайте резервные копии данных, которые хотите сохранить.</li>
+  <li>Следуйте инструкциям, приведенным на сайте
+<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>,
+чтобы прошить ваше устройство с использованием выбранного образа.</li>
+</ol>
+
+<p class="note">
+  <strong>Примечание.</strong> После прошивки устройства для разработки с использованием системного образа с предварительной версией платформы
+она будет автоматически обновлена до следующего выпуска Preview по беспроводной сети.
+</p>
+
+<h3 id="revertDevice">Сброс параметров устройства до заводских настроек</h3>
+
+<p>
+  Чтобы удалить Preview и восстановить заводские настройки устройства, перейдите на сайт
+<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a>
+и загрузите образ, который требуется использовать для прошивки. Следуйте инструкциям, приведенным на странице,
+чтобы прошить ваше устройство с использованием выбранного образа.
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/ru/preview/index.jd b/docs/html-intl/intl/ru/preview/index.jd
index 138a5a6..18174a9 100644
--- a/docs/html-intl/intl/ru/preview/index.jd
+++ b/docs/html-intl/intl/ru/preview/index.jd
@@ -29,7 +29,7 @@
 </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html-intl/intl/zh-cn/index.jd b/docs/html-intl/intl/zh-cn/index.jd
index bbd7fbe..cdd81cd 100644
--- a/docs/html-intl/intl/zh-cn/index.jd
+++ b/docs/html-intl/intl/zh-cn/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">准备迎接 Android 的下一版本。在 Nexus 5、
         6、9 和 Player 中测试应用。 </p>
 
@@ -31,7 +28,7 @@
           开始!</a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
         </a>
       </div>
     </div>
diff --git a/docs/html-intl/intl/zh-cn/preview/download.jd b/docs/html-intl/intl/zh-cn/preview/download.jd
index ba5249a..c7ba9df 100644
--- a/docs/html-intl/intl/zh-cn/preview/download.jd
+++ b/docs/html-intl/intl/zh-cn/preview/download.jd
@@ -164,13 +164,14 @@
   <div id="qv">
     <h2>本文内容</h2>
       <ol>
-        <li><a href="#sdk">预览版 SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">开发者文档</a></li>
         <li><a href="#images">硬件系统映像</a></li>
       </ol>
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+           <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -183,7 +184,7 @@
 </p>
 
 
-<h2 id="sdk">预览版 SDK</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   预览版 SDK 可通过 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下载。如需了解有关下载和配置预览版 SDK 的详细信息,请参阅<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">设置预览版 SDK</a>。
@@ -203,11 +204,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -240,34 +241,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/zh-cn/preview/download_mp2.jd b/docs/html-intl/intl/zh-cn/preview/download_mp2.jd
new file mode 100644
index 0000000..ba5249a
--- /dev/null
+++ b/docs/html-intl/intl/zh-cn/preview/download_mp2.jd
@@ -0,0 +1,359 @@
+page.title=下载
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">在下载和安装预览版 Android SDK 的组件之前,您必须同意下列条款和条件。
+</p>
+
+    <h2 class="norule">条款和条件</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+本协议是 Android SDK 预览版许可协议(以下称为“许可协议”)。
+
+1. 简介
+
+1.1 Android SDK 预览版(在本许可协议中简称为“预览版”,具体包括 Android 系统文件、封装 API 以及预览版库文件(若可用))依据本许可协议的条款授权您使用。本许可协议在您与 Google 之间就您对“预览版”的使用构成具有法律约束力的合约。
+
+1.2 “Android”是指以 Android 开源项目(项目网址为 http://source.android.com/,其内容会不时更新)名义提供、面向设备的 Android 软件栈。
+
+1.3 “Google”是指 Google Inc.,是一家特拉华州公司,主要营业地位于:1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。
+
+2. 接受许可协议
+
+2.1 要使用“预览版”,您必须先同意本许可协议。如果您不接受本许可协议,则不得使用“预览版”。
+
+2.2 点击接受并/或使用“预览版”,即表示您特此同意本许可协议的条款。
+
+2.3 如果依照美国或其他国家/地区(包括您居住或您使用“预览版”所在的国家/地区)的法律,您被禁止获取“预览版”,则您不得使用“预览版”,也不得接受本许可协议。
+
+2.4 如果您将在贵公司或组织内部使用“预览版”,则您同意代表您的雇主或其他实体接受本许可协议的约束,并且您表示并保证您拥有完全的合法授权令您的雇主或上述实体受本许可协议的约束。如果您不具备必要的授权,则不得代表您的雇主或其他实体接受本许可协议或使用“预览版”。
+
+3. Google 预览版许可
+
+3.1 Google 依据本许可协议的条款授予您个人或在贵公司或组织内部有限使用“预览版”的免版税、不可转让、非独占性、不可再授权且可撤销的许可,其用途仅限开发在 Android 平台上运行的应用。
+
+3.2 您同意 Google 或第三方拥有“预览版”中存在或相关的全部合法权利、所有权和利益,包括“预览版”中存在的任何知识产权。“知识产权”是指根据专利法、版权法、商业机密法、商标法享有的任何及全部权利,以及其他任何及全部专有权利。Google 保留所有未明确授予您的权利。
+
+3.3 您不得将“预览版”用于本许可协议未明确允许的任何用途。您不得:(a) 对“预览版”或“预览版”的任何部分进行复制(备份用途除外)、修改、改编、再分发、反编译、逆向工程、反汇编或创建其衍生品;或 (b) 将“预览版”的任何部分加载到移动手持终端或除个人计算机之外的任何其他硬件设备上,将“预览版”的任何部分与其他软件合并,或者发行任何融入“预览版”某一部分的软件或设备。
+
+3.4 您同意您将不会进行任何可能引起或导致 Android 碎片化的行动,包括但不限于分发、参与创建或以任何方式推广从“预览版”衍生的软件开发工具包。
+
+3.5 对于依据开源软件许可授权的“预览版”组件,其使用、复制和分发仅受该开源软件许可条款的制约,不受本许可协议的约束。您同意在依照被授予的所有权利作为被许可方期间,在遵守此类开源软件许可协议方面始终保持良好的信誉,并避免进行任何可能导致终止、暂停或违反此类权利的行动。
+
+3.6 您同意 Google 所提供“预览版”的形式和性质可随时发生变更,而无需事先通知您,并且未来的“预览版”版本可能会与在之前的“预览版”版本上开发的应用不兼容。您同意 Google 可单方面决定在未事先通知您的情况下全面停止(永久性或暂时性)向您或用户提供“预览版”(或“预览版”内的任何功能)。
+
+3.7 本许可协议内没有任何条款授予您使用 Google 的任何商品名、商标、服务标志、徽标、域名或其他独特品牌特征的权利。
+
+3.8 您同意您不会移除、遮盖或篡改“预览版”上可能贴有或“预览版”内可能包含的任何专有权利声明(包括版权声明和商标声明)。
+
+4. 您对“预览版”的使用
+
+4.1 Google 同意本许可协议中的任何条款均未授予 Google 从您(或您的许可方)处获取您依照本许可协议使用“预览版”开发的任何软件应用中存在或与其相关的权利、所有权或利益,包括这些应用中存在的任何知识产权。
+
+4.2 您同意只出于 (a) 本许可协议和 (b) 相关管辖区域内任何适用法律、法规或公认惯例或准则(包括有关向美国或其他相关国家/地区出口数据或软件或从美国或其他相关国家/地区进口数据或软件的任何法律)所允许的目的而使用“预览版”和编写应用。
+
+4.3 您同意,如果您使用“预览版”开发应用,您将会保护用户的隐私权和合法权利。如果用户向您提供用户名、密码或其他登录信息或个人信息,您必须确保用户知晓这些信息将供您的应用使用,并且您必须为这些用户提供足以满足法律要求的隐私声明和保护。如果您的应用存储由用户提供的个人信息或敏感信息,其存储方式必须安全。如果用户向您提供 Google 帐户信息,您的应用只能在用户允许时出于用户所许可的有限目的使用该信息访问用户的 Google 帐户。
+
+4.4 您同意您不会利用“预览版”从事任何干扰、中断、损坏或以未经授权方式访问 Google 或任何第三方的服务器、网络或其他财产或服务的Activity(包括应用的开发或分发)。
+
+4.5 您同意您对通过 Android 和/或 Android 应用创建、传输或显示的任何数据、内容或资源以及您的行为所导致的后果(包括 Google 可能遭受的任何损失或损害)负全责(Google 在上述方面对您或任何第三方不承担任何责任)。
+
+4.6 您同意您为违反本许可协议、任何适用的第三方合约或服务条款或任何适用法律或法规下的义务以及任何上述违规行为所导致的后果(包括 Google 或任何第三方可能遭受的任何损失或损害)负全责(Google 在上述方面对您或任何第三方不承担任何责任)。
+
+4.7 “预览版”正在开发中,您的测试和反馈是开发过程的重要环节。使用“预览版”,即表示您承认某些功能仍在开发实现之中,您不应期望“预览版”具备稳定版本的全部功能。您同意不使用此“预览版”公开发布或发运任何应用,因为此“预览版”在 Android SDK 正式发行之后将不再受支持。
+
+5. 您的开发者凭据
+
+5.1 您同意,对于 Google 可能向您发放或可能由您自行选择的任何开发者凭据,您有责任保持其机密性,并且您对以您的开发者凭据名义开发的所有应用负全责。
+
+6. 隐私权和信息
+
+6.1 为持续创新和改进“预览版”,Google 可能会从软件收集某些使用统计数据,包括但不限于唯一标识符、关联的 IP 地址、软件的版本号以及有关软件使用了“预览版”中哪些工具和/或服务及其使用方式的信息。在收集任何上述信息之前,“预览版”都会通知您并征求您的同意。如果您拒绝同意,我们将不会收集这些信息。
+
+6.2 我们会对收集的数据进行汇总调查,以便改进“预览版”,并会按照 Google 的隐私政策(网址为 http://www.google.com/policies/privacy/)维护数据。
+
+7. 第三方应用
+
+7.1 如果您使用“预览版”运行由第三方开发或访问由第三方提供的数据、内容或资源的应用,您同意 Google 对这些应用、数据、内容或资源不承担任何责任。您理解,您通过上述第三方应用可能访问到的所有数据、内容或资源由其提供者负全责,Google 对您因使用或访问其中任何第三方应用、数据、内容或资源而遭受的任何损失或损害不承担任何责任。
+
+7.2 您应知晓,通过此类第三方应用提供给您的数据、内容和资源可能受提供商(或代表他们的其他人员或公司)所拥有的知识产权的保护。除非相关所有者明确给予许可,否则您不得修改、出租、租赁、借出、出售、分发这些数据、内容或资源(的全部或部分),或以其为基础创建衍生品。
+
+7.3 您承认您对上述第三方应用、数据、内容或资源的使用可能受到您与相关第三方之间单独订立的条款的制约。
+
+8. 使用 Google API
+
+8.1 Google API
+
+8.1.1 如果您使用任何 API 从 Google 检索数据,即表示您承认这些数据可能受到 Google 或这些数据提供方(或代表他们的其他人员或公司)拥有的知识产权的保护。您对任何上述 API 的使用可能受到附加服务条款的制约。除非相关服务条款允许,否则您不得修改、出租、租赁、借出、出售、分发这些数据(的全部或部分),或以其为基础创建衍生品。
+
+8.1.2 如果您使用任何 API 从 Google 检索用户数据,即表示您承认并同意您只有在征得用户明确同意时才会检索数据,并且只能在用户允许时出于用户许可的有限目的检索数据。
+
+9. 终止许可协议
+
+9.1 本许可协议将持续有效,直至您或 Google 按以下规定终止本协议。
+
+9.2 如果您想终止本许可协议,可通过停止使用“预览版”以及任何相关开发者凭据予以终止。
+
+9.3 Google 有权在向您在作出通知后,有理由或无理由地随时终止与您订立的这份许可协议。
+
+9.4 本许可协议将在下列情况下自动终止,而无需另行通知或采取其他行动,以先符合条件者为准:
+(A) Google 在您居住或使用服务所在国家/地区停止向用户提供“预览版”或“预览版”的某些部分;
+(B) Google 发行 Android SDK 的最终版本。
+
+9.5 在本许可协议终止时,本许可协议中向您授予的许可将终止,您应立即完全停止使用“预览版”,并且第 10、11、12 和 14 节的条款将无限期继续存在。
+
+10. 免责声明
+
+10.1 您明确理解并同意,您使用“预览版”的风险将由您自行承担,并且“预览版”是按“原样”和“现状”提供,Google 不提供任何类型的担保。
+
+10.2 您对“预览版”的使用以及通过使用“预览版”下载或以其他方式获得的任何材料由您自行决定,风险自负,并且对于因此类使用而对您的计算机系统或其他设备造成的任何损害或数据损失由您单方面负责。在不对上文所述予以限制的条件下,您了解“预览版”并非稳定版本,可能存在将导致重大损害的错误、缺陷和安全漏洞,包括无法挽回地完全无法使用您的计算机系统或其他设备。
+
+10.3 Google 进一步明确拒绝任何类型的所有担保和条件,无论明示或暗示,包括但不限于有关适销性、特定用途适用性以及非侵权的暗示担保和条件。
+
+11. 有限责任
+
+11.1 您明确理解并同意,对于您可能遭遇的任何直接、间接、附带、特殊、继发或惩罚性损害(包括任何数据损失),Google 及其子公司和附属公司以及其许可方在任何责任理论下对您概不承担任何责任,无论 Google 或其代表是否已被告知或是否本应知晓发生任何上述损失的可能性。
+
+12. 赔偿
+
+12.1 您同意,在法律所允许的最大限度内,为 Google、其附属公司及其各自的董事、高管、员工和代理商提供辩护,使其免于因下列情况引起或产生的任何及所有索赔、诉讼、起诉或诉讼程序以及任何及所有损失、债务、损害、成本和费用(包括合理的律师费用)而承担责任或遭受损害:(a) 您对“预览版”的使用;(b) 您在“预览版”上开发的任何应用侵犯任何人的任何知识产权或诽谤任何人或侵犯其公开权或隐私权;以及 (c) 您的任何行为有悖于本许可协议
+
+13. 许可协议的更改
+
+13.1 Google 可能会在分发新版本“预览版”时对许可协议做出更改。做出这些更改后,Google 将在提供“预览版”的网站上公布新版本的许可协议。
+
+14. 一般法律条款
+
+14.1 本许可协议构成您与 Google 之间的完整法律协议,管辖您对“预览版”(不包括 Google 可能依据另外的书面协议向您提供的任何服务)的使用,并完全取代您之前与 Google 之间签订的、与“预览版”有关的任何协议。
+
+14.2 您同意,如果 Google 未行使或未强制执行本许可协议包含的任何法定权利或救济(或 Google 在任何适用法律下享有的相关利益),不得视为 Google 正式放弃这些权利,Google 仍可获得这些权利或救济。
+
+14.3 如果任何拥有管辖权的法院将本许可协议的任何条款裁定为无效,则该条款将从本许可协议中删除,而不会影响本许可协议的其余部分。本许可协议的其余条款将继续有效且可强制执行。
+
+14.4 您承认并同意,Google 集团旗下的每一家公司都将成为本许可协议的第三方受益人,并且此类其他公司将有权直接强制执行和依赖本许可协议中任何授予其利益(或支持其权利)的条款。除此之外,任何其他人员或公司均不得成为本许可协议的第三方受益人。
+
+14.5 出口限制。“预览版”受美国出口法律和法规的制约。您必须遵守适用于“预览版”的所有国内和国际出口法律和法规。这些法律包括目的地、最终用户和最终用途方面的限制。
+
+14.6 未经 Google 事先书面批准,您不得擅自转让或转移本许可协议,未经此类批准而试图进行的任何转让均为无效。未经 Google 事先书面批准,您不得委托您依据本许可协议所应承担的责任或义务。
+
+14.7 本许可协议以及您与 Google 依据本许可协议而建立的关系受加利福尼亚州法律管辖,而无论其是否与其他法律条款冲突。您与 Google 同意服从位于加利福尼亚州圣克拉拉县内法院的专属司法管辖权,以解决本许可协议引起的任何法律事务。尽管有上述规定,您同意仍允许 Google 在任何管辖区域申请禁令救济(或同等类型的紧急法律救济)。
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">我已阅读并同意上述条款和条件</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>本文内容</h2>
+      <ol>
+        <li><a href="#sdk">预览版 SDK</a></li>
+        <li><a href="#docs">开发者文档</a></li>
+        <li><a href="#images">硬件系统映像</a></li>
+      </ol>
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  Android M 预览版 SDK 包括开发工具、Android 系统文件和库文件,旨在帮助您在下一版本的平台中测试您的应用以及该平台提供的新 API。
+本文旨在介绍如何获得“预览版”的可下载组件,以便测试您的应用。
+
+</p>
+
+
+<h2 id="sdk">预览版 SDK</h2>
+
+<p>
+  预览版 SDK 可通过 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下载。如需了解有关下载和配置预览版 SDK 的详细信息,请参阅<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">设置预览版 SDK</a>。
+
+</p>
+
+
+<h2 id="docs">开发者文档</h2>
+
+<p>
+  开发者文档下载软件包提供详细的 API 参考信息和“预览版”的 API 差异报告。
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">硬件系统映像</h2>
+
+<p>
+  这些系统映像允许您在实际设备上安装预览版平台,以便进行测试。
+通过使用这些映像之一配置设备,您可以安装并测试您的应用,以了解其在下一版本平台上的性能表现。
+在设备上安装系统映像的过程会<em>删除设备中的所有数据</em>,因此您应该在安装系统映像之前备份数据。
+
+
+</p>
+
+<p class="warning">
+  <b>警告:</b>以下 Android 系统映像是预览版,可能会随时发生变化。您对这些系统映像的使用受 Android SDK 预览版许可协议的制约。
+Android 预览版系统映像并非稳定版本,可能包含会对您的计算机系统、设备和数据造成损害的错误和缺陷。
+
+Android 预览版系统映像未经过与出厂操作系统相同的测试,可能会导致您的手机和安装的服务与应用停止工作。
+
+
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">将映像安装到设备</h3>
+
+<p>
+  要使用设备映像进行测试,您必须将其安装到兼容设备上。请按照下面的说明安装系统映像:
+
+</p>
+
+<ol>
+  <li>下载并解压此处列出的系统映像包之一。</li>
+  <li>备份设备中您希望予以保留的任何数据。</li>
+  <li>按照
+<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+ 中的说明将映像刷入设备中。</li>
+</ol>
+
+<p class="note">
+  <strong>注:</strong>为开发设备刷入预览版系统映像之后,它将通过无线 (OTA) 更新自动升级到下一个预览版本。
+
+</p>
+
+<h3 id="revertDevice">将设备还原至出厂规格</h3>
+
+<p>
+  如果您想要卸载预览版并将设备还原至出厂规格,请转到
+<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> 并下载要为设备刷入的映像。
+按照该页面上的说明将映像刷入设备中。
+
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/zh-cn/preview/index.jd b/docs/html-intl/intl/zh-cn/preview/index.jd
index 36ad718..caed4cb 100644
--- a/docs/html-intl/intl/zh-cn/preview/index.jd
+++ b/docs/html-intl/intl/zh-cn/preview/index.jd
@@ -29,7 +29,7 @@
 </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html-intl/intl/zh-tw/index.jd b/docs/html-intl/intl/zh-tw/index.jd
index 53bbd8d..cf1376f 100644
--- a/docs/html-intl/intl/zh-tw/index.jd
+++ b/docs/html-intl/intl/zh-tw/index.jd
@@ -10,19 +10,16 @@
 <section class="dac-hero-carousel">
 
 <!-- <article class="dac-expand dac-hero dac-invert active" style="background-color: rgb(38, 50, 56);"> -->
-<article class="dac-expand dac-hero dac-invert active" style="background-color: #455A64;">
+<article class="dac-expand dac-hero dac-invert dac-darken mprev active" style="background-color: #75d1ff;">
 <a href="/preview/index.html">
-  <div class="wrap" style="max-width:1100px;">
+  <div class="wrap" style="max-width:1100px;margin-top:0">
     <div class="cols dac-hero-content">
-      <div class="col-10of16 col-push-6of16 dac-hero-figure">
-        <img class="dac-hero-image" src="{@docRoot}images/home/devices-hero_620px_2x.png"
-             srcset="{@docRoot}images/home/devices-hero_620px.png 1x,
-             {@docRoot}images/home/devices-hero_620px_2x.png 2x">
+      <div class="col-8of16 col-push-6of16 dac-hero-figure mprev">
       </div>
-      <div class="col-6of16 col-pull-10of16">
+      <div class="col-8of16 col-pull-7of16">
         <div class="dac-hero-tag"></div>
 
-        <h1 class="dac-hero-title">Android M Developer Preview</h1>
+        <h1 class="dac-hero-title" style="white-space:nowrap;">Android 6.0 Marshmallow</h1>
         <p class="dac-hero-description">準備使用新版 Android。在 Nexus 5、6、9 和
         Player 上測試您的應用程式。 </p>
 
@@ -32,7 +29,7 @@
         </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
   </div>
diff --git a/docs/html-intl/intl/zh-tw/preview/download.jd b/docs/html-intl/intl/zh-tw/preview/download.jd
index 3b54080..163af2c 100644
--- a/docs/html-intl/intl/zh-tw/preview/download.jd
+++ b/docs/html-intl/intl/zh-tw/preview/download.jd
@@ -164,13 +164,14 @@
   <div id="qv">
     <h2>本文件內容</h2>
       <ol>
-        <li><a href="#sdk">預覽版 SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">開發人員文件</a></li>
         <li><a href="#images">硬體系統映像</a></li>
       </ol>
      <h2>Legacy downloads</h2>
         <ol>
-           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview 1</a></li>
+           <li><a href="{@docRoot}preview/download_mp2.html">Developer Preview 2</a></li>
         </ol>
   </div>
 </div>
@@ -183,7 +184,7 @@
 </p>
 
 
-<h2 id="sdk">預覽版 SDK</h2>
+<h2 id="sdk">Android 6.0 SDK</h2>
 
 <p>
   預覽版 SDK 可透過 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下載取得。如需有關下載和設定預覽版 SDK 的詳細資訊,請參閱<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">設定預覽版 SDK</a>。
@@ -203,11 +204,11 @@
     <th scope="col">Download / Checksums</th>
   </tr>
   <tr id="docs-dl">
-    <td>Android M Preview 2<br>Developer Docs</td>
+    <td>Android M Preview 3<br>Developer Docs</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >m-preview-2-developer-docs.zip</a><br>
-      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
-      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+      >m-preview-3-developer-docs.zip</a><br>
+      MD5: d99b14b0c06d31c8dfecb25072654ca3<br>
+      SHA-1: 9cefeeda07676130da606a1796e1c00fffc667c1
     </td>
   </tr>
 </table>
@@ -240,34 +241,34 @@
   <tr id="hammerhead">
     <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
-      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
-      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+      >hammerhead-MPA44I-preview-2ebbc049.tgz</a><br>
+      MD5: 91a924fb0c9f8e716e3b4c9954fd0dbb<br>
+      SHA-1: 2ebbc049b68c4da8baeee3e42bb94d7a965ba4a3
     </td>
   </tr>
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
-      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
-      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+      >shamu-MPA44I-preview-62b9c486.tgz</a><br>
+      MD5: ac6e58da86125073d9c395257fd42664<br>
+      SHA-1: 62b9c486fd7a5020e228d53ca5acd5c1857e48ff
     </td>
   </tr>
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
-      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
-      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+      >volantis-MPA44I-preview-5c30a6e2.tgz</a><br>
+      MD5: 7f83768757913d3fea945a661020d185<br>
+      SHA-1: 5c30a6e2acd11a81f4105b12d23ff654f534f699
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
-      MD5: e8d081137a20b66df595ee69523314b5<br>
-      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+      >fugu-MPA44I-preview-2860040a.tgz</a><br>
+      MD5: 438da8d37da9e341a69cfb16a4001ac5<br>
+      SHA-1: 2860040a326582f1ff5f702bf9a1ef002717fc98
     </td>
   </tr>
 
diff --git a/docs/html-intl/intl/zh-tw/preview/download_mp2.jd b/docs/html-intl/intl/zh-tw/preview/download_mp2.jd
new file mode 100644
index 0000000..3b54080
--- /dev/null
+++ b/docs/html-intl/intl/zh-tw/preview/download_mp2.jd
@@ -0,0 +1,359 @@
+page.title=下載
+page.image=images/cards/card-download_16-9_2x.png
+
+@jd:body
+
+<div style="position:relative; min-height:600px">
+
+  <div class="wrap" id="tos" style="position:absolute;display:none;width:inherit;">
+
+    <p class="sdk-terms-intro">在下載和安裝 Android 預覽版
+SDK 的元件之前 ,您必須同意遵守下列條款和條件。</p>
+
+    <h2 class="norule">條款和條件</h2>
+
+    <div class="sdk-terms" onfocus="this.blur()" style="width:678px">
+這是「Android SDK 預覽版授權協議」(以下稱「授權協議」)。
+
+1.簡介
+
+1.1「Android SDK 預覽版」(在「授權協議」中稱為「預覽版」,包括 (如果有可用的) Android 系統檔案、經過封裝的 API 和預覽版程式庫檔案) 是在「授權協議」之條款的約束下授權給您使用。「授權協議」就您對「預覽版」的使用,構成您與 Google 間具法律約束力之合約。
+
+1.2「Android」係指「Android 軟體開放原始碼專案」(http://source.android.com/) 所提供的 Android 裝置軟體堆疊 (不定期更新)。
+
+1.3「Google」係指 Google Inc.,是一家在美國德拉瓦州註冊的公司,地址為 1600 Amphitheatre Parkway, Mountain View, CA 94043, United States。
+
+2.接受「授權協議」
+
+2.1 必須先同意遵守「授權協議」,才能使用此「預覽版」。如果不接受「授權協議」,您就無法使用此「預覽版」。
+
+2.2 按一下 [接受] 且/或使用「預覽版」,即表示您同意「授權協議」的條款。
+
+2.3 如果您是美國或其他國家/地區 (包括您所居住或使用此「預覽版」的國家/地區) 的法律所禁止接收此「預覽版」的人員,就不得使用此「預覽版」及接受「授權協議」。
+
+2.4 如果您將在公司或組織內部使用「預覽版」,您就要代表雇主或其他實體同意受「授權協議」約束,且您代表並保證具備完整法定權限來約束您的雇主或這類實體遵守「授權協議」。如果您不具備必要的權限,就不得代表您的雇主或其他實體接受「授權協議」或使用此「預覽版」。
+
+3.Google 的預覽版授權
+
+3.1 在「授權協議」之條款的約束下,Google 授權您使用此「預覽版」,此授權為買斷式、不可轉讓、非獨占性、不可轉授權、有限且可撤銷,僅在您公司或組織內部私下或內部使用。此「預覽版」僅供您用於開發在 Android 平台上執行的應用程式。
+
+3.2 您同意 Google 或第三方對此「預覽版」擁有一切法定權利及權益,包括存在於此「預覽版」中的任何「智慧財產權」。「智慧財產權」係指專利法、著作權法、商業秘密法、商標法及任何和所有其他專利權下的任何及一切權利。Google 保留一切未明確授予您的權利。
+
+3.3 您不得將此「預覽版」用於「授權協議」未明文許可的任何用途。除非適用的第三方授權所需,否則您不得:(a) 對此「預覽版」或其任何部分進行複製 (備份用途除外)、修改、改編、轉散佈、反向組譯、還原工程、解編或製作衍生成品;或是 (b) 將此「預覽版」的任何部分載入至行動電話或個人電腦以外的任何其他硬體裝置、將此「預覽版」的任何部分與其他軟體結合,或散佈包含此「預覽版」之任一部分的任何軟體或裝置。
+
+3.4 您同意不會從事任何可能導致或造成 Android 分裂的活動,包括但不限於以任何形式散佈從此「預覽版」衍生的軟體開發套件、參其製作或宣傳。
+
+3.5 對開放原始碼軟體授權下所授權之「預覽版」的使用、複製及散佈,完全受該開放原始碼軟體授權的條款管制,而不受「授權協議」管制。您同意遵守從這類開放原始碼軟體授權獲得的所有權利,並且避免採取任何可能終止、中止或侵害這類權利的行為。
+
+3.6 您同意 Google 可在不事先通知您的情況下變更其所提供之「預覽版」的形式和本質,且此「預覽版」的未來版本可與在此「預覽版」的先前版本上開發的應用程式不相容。您同意 Google 通常可全權斟酌永久或暫時停止提供此「預覽版」(或此「預覽版」的任何功能) 給您或使用者,毋須事先通知。
+
+3.7「授權協議」中的所有條款皆未授予您任何使用 Google 之商業名稱、商標、服務標章、標誌、網域名稱或其他明確品牌特徵的權利。
+
+3.8 您同意不會移除、遮蔽或更改可能附加至或內含在此「預覽版」中的任何專利權通知 (包括著作權和商標通知)。
+
+4.您對「預覽版」的使用
+
+4.1 Google 同意在「授權協議」下,任何條款皆未從您 (或您的授權人) 賦予 Google 對您使用此「預覽版」開發之任何軟體應用程式的任何權利及權益,包括存在於這些應用程式中的任何智慧財產權。
+
+4.2 您同意只就 (a)「授權協議」和 (b) 相關管轄權中任何適用法律、規定或是普遍獲得接受之慣例或指導方針 (包括任何有關將資料或軟體輸出或輸入美國或其他相關國家/地區的法律) 所允許的用途使用此「預覽版」及撰寫應用程式。
+
+4.3 您同意如果使用此「預覽版」開發應用程式,您將保護使用者的隱私權和法定權利。如果使用者提供您使用者名稱、密碼或是其他登入資訊或個人資訊,您必須告知使用者這類資訊將提供給您的應用程式使用,並且必須為這些使用者提供法定充分的隱私權通知和保護。如果您的應用程式會儲存使用者所提供的個人或敏感資訊,它必須確保這些資訊安全無虞。如果使用者提供 Google 帳戶資訊給您,則只有在每個使用者已授權您存取其 Google 帳戶並僅限用於使用者所授權之用途的情況下,您的應用程式才能使用該資訊來存取使用者的 Google 帳戶。
+
+4.4 您同意不會使用此「預覽版」從事任何不當Activity,例如開發或散佈會以未經授權的方式干擾、妨礙、損害或存取 Google 或任何第三方之伺服器、網路或是其他財產或服務的應用程式。
+
+4.5 您同意對您透過 Android 裝置和 (或) Android 應用程式建立、傳輸或顯示的任何資料、內容或資源,以及上述行為造成的後果 (包括 Google 可能蒙受的任何損失或損害) 負起全責 (而 Google 對您或任何第三方就上述一切不需負任何責任)。
+
+4.6 您同意對違反在此「授權協議」、任何適用之第三方合約或《服務條款》或是任何適用之法律或規定下所必須遵守的義務,以及違反相關義務造成的後果 (包括 Google 或任何第三方可能蒙受的任何損失或損害) 負起全責 (而 Google 對您或任何第三方就上述一切不需負任何責任)。
+
+4.7「預覽版」目前正在開發中,因此您的測試與意見反應對開發程序非常重要。使用「預覽版」,您即認同某些功能仍處於開發階段,因此您不應期待「預覽版」擁有穩定版本的完整功能。在官方 Android SDK 發行之後,此「預覽版」不再受到支援時,您同意不使用此「預覽版」公開散佈或隨附任何應用程式。
+
+5.您的開發人員認證
+
+5.1 您同意負責保密 Google 可能核發給您或您自己選擇的任何開發人員認證,並且對在您開發人員認證名義下開發的所有應用程式負起全責。
+
+6.隱私權和資訊
+
+6.1 為了持續更新及改進此「預覽版」,Google 可能會從軟體收集某些使用狀況統計數據,包括但不限於軟體的唯一識別碼、相關 IP 位址、版本號碼,以及有關使用此「預覽版」中的哪些工具和 (或) 服務及其使用方式的相關資訊。在收集這類資訊之前,此「預覽版」會先通知您並徵求您的同意。如果您不同意,Google 將不會收集這類資訊。
+
+6.2 Google 會彙總並檢查收集到的資料,據以改善此「預覽版」,並且會依據《Google 隱私權政策》(http://www.google.com/policies/privacy/) 加以妥善保存。
+
+7.第三方應用程式
+
+7.1 如果您使用此「預覽版」來執行第三方開發的應用程式,或是執行會存取第三方所提供之資料、內容或資源的應用程式,您同意 Google 不需對這類應用程式、資料、內容或資源負任何責任。您瞭解您透過第三方應用程式存取的所有資料、內容或資源是由其提供者負起全責,而 Google 對您因使用或存取任何這些第三方應用程式、資料、內容或資源所造成的損失或損害不需負任何責任。
+
+7.2 您瞭解第三方應用程式提供給您的資料、內容或資源可能受到提供者 (或代表他們的其他人員或公司) 所擁有的智慧財產權保護。您不得根據這類資料、內容或資源 (不論是整個或部分) 修改、出租、出借、販售、散佈或製作衍生成品,除非相關擁有者明確授權您從事上述活動。
+
+7.3 您瞭解使用第三方應用程式、資料、內容或資源可能受到您與相關第三方之間的個別條款約束。
+
+8.使用 Google API
+
+8.1 Google API
+
+8.1.1 如果您使用任何 API 從 Google 擷取資料,您瞭解這些資料可能受到 Google 或資料提供者 (或代表他們的其他人員或公司) 所擁有的智慧財產權保護。您對任何這類 API 的使用可能受到其他《服務條款》約束。除非相關《服務條款》明文允許,否則您不得根據這類資料 (不論是整個或部分) 修改、出租、出借、販售、散佈或製作衍生成品。
+
+8.1.2 使用任何 API 從 Google 擷取使用者的資料時,您瞭解並同意只有在該使用者明確同意且授權您擷取其資料,而且僅限用於使用者所授權之用途的情況下,您才能擷取資料。
+
+9.終止「授權協議」
+
+9.1 除非您或 Google 終止「授權協議」(請見下方說明),否則「授權協議」將持續具有效力。
+
+9.2 如果想終止「授權協議」,只要停止使用此「預覽版」及任何相關的開發人員憑證即可。
+
+9.3 Google 可隨時通知您終止「授權協議」,無論有無原因。
+
+9.4「授權協議」在先發生下列任一情況時,將自動終止而不另行通知或採取其他行動:
+(A) Google 決定不再提供此「預覽版」或此「預覽版」的特定部分給您所居住或使用此服務之國家/地區的使用者;或
+(B) Google 發行最終版本的 Android SDK。
+
+9.5 當「授權條款」終止時,您在「授權協議」所獲得的授權也將會一併終止,您將立即停止「預覽版」的所有使用,而第 10、11、12 和 14 項的條款將無限期持續適用。
+
+10.免責聲明
+
+10.1 您明確瞭解並同意完全自負使用此「預覽版」的風險,並且此「預覽版」是依「現況」和「可提供性」提供,Google 不負任何擔保責任。
+
+10.2 您對使用此「預覽版」及透過此「預覽版」以下載或其他方式取得的任何內容,需自行斟酌和自負風險,而且您對因這類使用而對您的電腦系統或其他裝置所造成的任何損害或資料遺失,需負起全責。不限於前述,您瞭解此「預覽版」不是穩定的版本,可能會包含許多錯誤、瑕疵和安全性弱點而對您的電腦系統或其他裝置造成嚴重的損害,包括完全、不可回復的損失。
+
+10.3 Google 進一步明確表示不提供任何形式的瑕疵擔保和條件 (不論明示或默示),包括但不限於適售性、適合特定用途及未侵權的默示擔保和條件。
+
+11.責任限制
+
+11.1 您明確瞭解並同意在任何歸責理論下,就可能由您引起的任何直接、間接、附隨性、特殊性、衍生性或懲罰性損害賠償 (包括任何資料遺失),不論 Google 或其代表是否已獲告知或應已瞭解發生任何這類損失的可能性,Google、其子公司和關係企業及其授權人不必對您負起任何責任。
+
+12.賠償
+
+12.1 在法律允許的最大範圍內,您同意為 Google、其子公司及其個別董監事、主管、員工和代理人,就任何和一切索賠、法律行動、訴訟或訴訟程序,以及因下列原因而引起的任何和一切損失、責任、損害賠償、費用及開支 (包括合理的律師費),提供辯護、賠償損失並確保其免於承擔賠償責任:(a) 您使用此「預覽版」;(b) 您使用此「預覽版」開發的應用程式侵害任何人的任何智慧財產權,或是詆毀任何人或違反其公開權或隱私權;以及 (c) 您未遵守「授權協議」。
+
+13.對「授權協議」做出的變更
+
+13.1 Google 可在散佈此「預覽版」的新版本時修改「授權協議」。做出這類變更後,Google 會在提供此「預覽版」的網站上提供「授權協議」的新版本。
+
+14.一般法律條款
+
+14.1「授權協議」構成您與 Google 之間的法律協議,用於管制您對此「預覽版」(不包括 Google 依據個別書面協議提供給您的任何服務) 的使用,並完全取代先前您與 Google 之間就此「預覽版」簽署的相關協議。
+
+14.2 您同意如果 Google 未行使或執行「授權協議」所含的任何法律權利或救濟 (或在任何適用法律下對 Google 有利的權益),並不代表 Google 正式放棄權利,Google 日後仍可行使這些權利或救濟。
+
+14.3 如果經任何法院 (就此事宜依管轄權決定) 裁決「授權協議」中有任何條款無效,則該條款將自「授權協議」中移除,「授權協議」的其餘部分則不受影響。「授權協議」的其餘條款將持續具有效力且可執行。
+
+14.4 您瞭解並同意 Google 旗下子公司體系的每位成員都是「授權協議」的第三方受益人,而且這類其他公司有權直接執行和依據「授權協議」中對其授予權益 (或對其有利之權利) 的任何條款。除此之外的任何其他人員或公司皆非「授權協議」的第三方受益人。
+
+14.5 出口限制。此「預覽版」受美國出口法規約束。您必須遵守適用於此「預覽版」的所有國內和國際出口法規。這些法律包括對目的地、使用者及最終用途的限制。
+
+14.6 未事先取得 Google 事先書面核准的情況下,您不得轉讓或轉移「授權協議」,未經這類核准的任何轉讓將會失效。您不得在未事先取得 Google 書面核准的情況下,委派其「授權協議」涵蓋的責任或義務。
+
+14.7「授權協議」以及您與 Google 就「授權協議」構成的關係皆受加州法律管轄,毋須理會其法律牴觸條款。您和 Google 同意服從位於加州聖塔克拉拉 (Santa Clara, California) 郡內法院的專屬管轄權,以解決由「授權協議」產生的任何法律事務。儘管如此,您同意 Google 仍可在任何管轄權中申請禁制令救濟 (或同等類型的緊急法定救濟)。
+  </div><!-- sdk terms -->
+
+
+
+    <div id="sdk-terms-form">
+      <p>
+        <input id="agree" type="checkbox" name="agree" value="1" onclick="onAgreeChecked()" />
+        <label id="agreeLabel" for="agree">我已閱讀並同意上述條款及細則</label>
+      </p>
+      <p><a href="" class="button disabled" id="downloadForRealz" onclick="return onDownloadForRealz(this);"></a></p>
+    </div>
+
+
+  </div><!-- end TOS -->
+
+
+  <div id="landing">
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>本文件內容</h2>
+      <ol>
+        <li><a href="#sdk">預覽版 SDK</a></li>
+        <li><a href="#docs">開發人員文件</a></li>
+        <li><a href="#images">硬體系統映像</a></li>
+      </ol>
+     <h2>Legacy downloads</h2>
+        <ol>
+           <li><a href="{@docRoot}preview/download_mp1.html">Developer Preview Archive</a></li>
+        </ol>
+  </div>
+</div>
+
+
+<p>
+  Android M 預覽版 SDK 有開發工具、Android 系統檔案以及程式庫檔案,可以幫助測試您的應用程式和下一個平台版本隨附的新 API。
+本文件會說明如何取得可下載的預覽版元件來測試您的應用程式。
+
+</p>
+
+
+<h2 id="sdk">預覽版 SDK</h2>
+
+<p>
+  預覽版 SDK 可透過 <a href="{@docRoot}tools/help/sdk-manager.html">Android SDK 管理器</a>下載取得。如需有關下載和設定預覽版 SDK 的詳細資訊,請參閱<a href="{@docRoot}preview/setup-sdk.html#downloadSdk">設定預覽版 SDK</a>。
+
+</p>
+
+
+<h2 id="docs">開發人員文件</h2>
+
+<p>
+  開發人員文件下載套件提供詳細的 API 參考資料和預覽版的 API 差異報告。
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Description</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="docs-dl">
+    <td>Android M Preview 2<br>Developer Docs</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >m-preview-2-developer-docs.zip</a><br>
+      MD5: 1db6fff9c722b0339757e1cdf43663a8<br>
+      SHA-1: 5a4ae88d644e63824d21b0e18f8e3977a7665157
+    </td>
+  </tr>
+</table>
+
+
+<h2 id="images">硬體系統映像</h2>
+
+<p>
+  這些系統映像可以讓您在實體裝置上安裝預覽版的平台來進行測試。
+使用其中一個映像設定裝置,您就可以安裝並測試您的應用程式,瞭解應用程式在下一個版本的平台上表現如何。
+在裝置上安裝系統映像的過程中,會「移除裝置當中所有的資料」,因此您應該在安裝系統映像之前備份您的資料。<em></em>
+
+
+</p>
+
+<p class="warning">
+  <b>警告:</b>下列 Android 系統映像是預覽版,可能隨時會有變更。使用這些系統映像受到「Android SDK 預覽版授權協議」的約束。
+Android 預覽版系統映像還不是穩定的版本,可能會包含許多錯誤和瑕疵而對您的電腦系統、裝置和資料造成損害。
+
+預覽版的 Android 系統映像與出廠作業系統的測試不同,可能會導致您的手機和安裝的服務與應用程式停止運作。
+
+
+</p>
+
+<table>
+  <tr>
+    <th scope="col">Device</th>
+    <th scope="col">Download / Checksums</th>
+  </tr>
+  <tr id="hammerhead">
+    <td>Nexus 5 (GSM/LTE) <br>"hammerhead"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >hammerhead-MPZ79M-preview-b1f4bde4.tgz</a><br>
+      MD5: 2ca9f18bf47a061b339bab52647ceb0d<br>
+      SHA-1: b1f4bde447eccbf8ce5d9b8b8ba954e3eac8e939
+    </td>
+  </tr>
+  <tr id="shamu">
+    <td>Nexus 6 <br>"shamu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >shamu-MPZ79M-preview-e1024040.tgz</a><br>
+      MD5: 24a2118da340b9afedfbdfc026f6ff81<br>
+      SHA-1: e10240408859d5188c4aae140e1c539130ba614b
+    </td>
+  </tr>
+  <tr id="volantis">
+    <td>Nexus 9 <br>"volantis"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >volantis-MPZ79M-preview-9f305342.tgz</a><br>
+      MD5: 9edabf0a4c61b247f1cbb9dfdc0a899e<br>
+      SHA-1: 9f30534216f10899a6a75495fc7e92408ea333a7
+    </td>
+  </tr>
+
+  <tr id="fugu">
+    <td>Nexus Player <br>"fugu"</td>
+    <td><a href="#top" onclick="onDownload(this)"
+      >fugu-MPZ79N-preview-fb63af98.tgz</a><br>
+      MD5: e8d081137a20b66df595ee69523314b5<br>
+      SHA-1: fb63af98302dd97be8de9313734d389ccdcce250
+    </td>
+  </tr>
+
+</table>
+
+<h3 id="install-image">在裝置上安裝映像</h3>
+
+<p>
+  如果要使用裝置映像進行測試,您必須先在相容的裝置上安裝映像。請依照下面的指示安裝系統映像:
+
+</p>
+
+<ol>
+  <li>下載此處列出的其中一個系統映像,然後解壓縮。</li>
+  <li>備份您要保留的所有裝置資料。</li>
+  <li>依照
+<a href="https://developers.google.com/android/nexus/images#instructions">developers.google.com/android</a>
+的指示,將映像更新到您的裝置。</li>
+</ol>
+
+<p class="note">
+  <strong>注意:</strong>在您使用預覽版系統映像更新開發裝置之後,裝置就會透過無線 (OTA) 更新方式自動升級為下一個預覽版版本。
+
+</p>
+
+<h3 id="revertDevice">將裝置還原成出廠規格</h3>
+
+<p>
+  如果您要解除安裝預覽版並將裝置還原成出廠規格,請至
+<a href="http://developers.google.com/android/nexus/images">developers.google.com/android</a> 並下載您要為裝置更新的映像。
+依照該頁面的指示,將映像更新到您的裝置。
+
+</p>
+
+  </div><!-- landing -->
+
+</div><!-- relative wrapper -->
+
+
+
+<script>
+  var urlRoot = "http://storage.googleapis.com/androiddevelopers/shareables/preview/";
+  function onDownload(link) {
+
+    $("#downloadForRealz").html("Download " + $(link).text());
+    $("#downloadForRealz").attr('href', urlRoot + $(link).text());
+
+    $("#tos").fadeIn('fast');
+    $("#landing").fadeOut('fast');
+
+    return true;
+  }
+
+
+  function onAgreeChecked() {
+    /* verify that the TOS is agreed */
+    if ($("input#agree").is(":checked")) {
+      /* reveal the download button */
+      $("a#downloadForRealz").removeClass('disabled');
+    } else {
+      $("a#downloadForRealz").addClass('disabled');
+    }
+  }
+
+  function onDownloadForRealz(link) {
+    if ($("input#agree").is(':checked')) {
+    /*
+      $("#tos").fadeOut('fast');
+      $("#landing").fadeIn('fast');
+    */
+
+      ga('send', 'event', 'M Preview', 'System Image', $("#downloadForRealz").html());
+
+    /*
+      location.hash = "";
+    */
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  $(window).hashchange( function(){
+    if (location.hash == "") {
+      location.reload();
+    }
+  });
+
+</script>
diff --git a/docs/html-intl/intl/zh-tw/preview/index.jd b/docs/html-intl/intl/zh-tw/preview/index.jd
index a9cf1ae..3aaf382 100644
--- a/docs/html-intl/intl/zh-tw/preview/index.jd
+++ b/docs/html-intl/intl/zh-tw/preview/index.jd
@@ -29,7 +29,7 @@
 </a><br>
         <a class="dac-hero-cta" href="{@docRoot}preview/support.html">
           <span class="dac-sprite dac-auto-chevron"></span>
-          Developer Preview 2</a>
+          Developer Preview 3 (final SDK)</a>
       </div>
     </div>
     <div class="dac-section dac-small">
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index ecc0c7e..d00f90cbf 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -164,7 +164,7 @@
   <div id="qv">
     <h2>In this document</h2>
       <ol>
-        <li><a href="#sdk">Developer Preview 3 SDK</a></li>
+        <li><a href="#sdk">Android 6.0 SDK</a></li>
         <li><a href="#docs">Developer Documentation</a></li>
         <li><a href="#images">Hardware System Images</a></li>
       </ol>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index c5d68bd..ce35b87 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,10 +17,13 @@
 package android.graphics;
 
 import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Size;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
 import android.text.SpannedString;
 import android.text.TextUtils;
+import android.util.LocaleList;
 
 import java.util.Locale;
 
@@ -50,7 +53,7 @@
     private float       mCompatScaling;
     private float       mInvCompatScaling;
 
-    private Locale      mLocale;
+    private LocaleList  mLocales;
     private String      mFontFeatureSettings;
 
     /**
@@ -434,7 +437,7 @@
         // setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
         //        ? HINTING_OFF : HINTING_ON);
         mCompatScaling = mInvCompatScaling = 1;
-        setTextLocale(Locale.getDefault());
+        setTextLocales(LocaleList.getDefault());
     }
 
     /**
@@ -474,7 +477,7 @@
         mInvCompatScaling = 1;
 
         mBidiFlags = BIDI_DEFAULT_LTR;
-        setTextLocale(Locale.getDefault());
+        setTextLocales(LocaleList.getDefault());
         setElegantTextHeight(false);
         mFontFeatureSettings = null;
     }
@@ -512,7 +515,7 @@
         mInvCompatScaling = paint.mInvCompatScaling;
 
         mBidiFlags = paint.mBidiFlags;
-        mLocale = paint.mLocale;
+        mLocales = paint.mLocales;
         mFontFeatureSettings = paint.mFontFeatureSettings;
     }
 
@@ -1174,47 +1177,80 @@
     }
 
     /**
-     * Get the text Locale.
+     * Get the text's primary Locale. Note that this is not all of the locale-related information
+     * Paint has. Use {@link #getTextLocales()} to get the complete list.
      *
-     * @return the paint's Locale used for drawing text, never null.
+     * @return the paint's primary Locale used for drawing text, never null.
      */
+    @NonNull
     public Locale getTextLocale() {
-        return mLocale;
+        return mLocales.getPrimary();
     }
 
     /**
-     * Set the text locale.
+     * Get the text locale list.
      *
-     * The text locale affects how the text is drawn for some languages.
+     * @return the paint's LocaleList used for drawing text, never null or empty.
+     */
+    @NonNull @Size(min=1)
+    public LocaleList getTextLocales() {
+        return mLocales;
+    }
+
+    /**
+     * Set the text locale list to a one-member list consisting of just the locale.
      *
-     * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
+     * See {@link #setTextLocales(LocaleList)} for how the locale list affects
+     * the way the text is drawn for some languages.
+     *
+     * @param locale the paint's locale value for drawing text, must not be null.
+     */
+    public void setTextLocale(@NonNull Locale locale) {
+        if (locale == null) {
+            throw new IllegalArgumentException("locale cannot be null");
+        }
+        if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.getPrimary())) {
+            return;
+        }
+        mLocales = new LocaleList(locale);
+        native_setTextLocale(mNativePaint, locale.toString());
+    }
+
+    /**
+     * Set the text locale list.
+     *
+     * The text locale list affects how the text is drawn for some languages.
+     *
+     * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA},
      * then the text renderer will prefer to draw text using a Chinese font. Likewise,
-     * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
-     * renderer will prefer to draw text using a Japanese font.
+     * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
+     * renderer will prefer to draw text using a Japanese font. If the locale list contains both,
+     * the order those locales appear in the list is considered for deciding the font.
      *
      * This distinction is important because Chinese and Japanese text both use many
      * of the same Unicode code points but their appearance is subtly different for
      * each language.
      *
-     * By default, the text locale is initialized to the system locale (as returned
-     * by {@link Locale#getDefault}). This assumes that the text to be rendered will
-     * most likely be in the user's preferred language.
+     * By default, the text locale list is initialized to a one-member list just containing the
+     * system locale (as returned by {@link LocaleList#getDefault()}). This assumes that the text to
+     * be rendered will most likely be in the user's preferred language.
      *
-     * If the actual language of the text is known, then it can be provided to the
-     * text renderer using this method. The text renderer may attempt to guess the
+     * If the actual language or languages of the text is/are known, then they can be provided to
+     * the text renderer using this method. The text renderer may attempt to guess the
      * language script based on the contents of the text to be drawn independent of
-     * the text locale here. Specifying the text locale just helps it do a better
-     * job in certain ambiguous cases
+     * the text locale here. Specifying the text locales just helps it do a better
+     * job in certain ambiguous cases.
      *
-     * @param locale the paint's locale value for drawing text, must not be null.
+     * @param locales the paint's locale list for drawing text, must not be null or empty.
      */
-    public void setTextLocale(Locale locale) {
-        if (locale == null) {
-            throw new IllegalArgumentException("locale cannot be null");
+    public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+        if (locales == null || locales.isEmpty()) {
+            throw new IllegalArgumentException("locales cannot be null or empty");
         }
-        if (locale.equals(mLocale)) return;
-        mLocale = locale;
-        native_setTextLocale(mNativePaint, locale.toString());
+        if (locales.equals(mLocales)) return;
+        mLocales = locales;
+        // TODO: Pass the whole LocaleList to native code
+        native_setTextLocale(mNativePaint, locales.getPrimary().toString());
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1857345..abb51db 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -217,7 +217,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         return mAnimatedVectorState.mVectorDrawable.setLevel(level);
     }
 
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index e1975c9..521c74b 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -105,10 +105,12 @@
     /**
      * Sets whether this AnimationDrawable is visible.
      * <p>
-     * When the drawable becomes invisible, it will pause its animation. A
-     * subsequent change to visible with <code>restart</code> set to true will
-     * restart the animation from the first frame. If <code>restart</code> is
-     * false, the animation will resume from the most recent frame.
+     * When the drawable becomes invisible, it will pause its animation. A subsequent change to
+     * visible with <code>restart</code> set to true will restart the animation from the
+     * first frame. If <code>restart</code> is false, the drawable will resume from the most recent
+     * frame. If the drawable has already reached the last frame, it will then loop back to the
+     * first frame, unless it's a one shot drawable (set through {@link #setOneShot(boolean)}),
+     * in which case, it will stay on the last frame.
      *
      * @param visible true if visible, false otherwise
      * @param restart when visible, true to force the animation to restart
@@ -120,7 +122,7 @@
         final boolean changed = super.setVisible(visible, restart);
         if (visible) {
             if (restart || changed) {
-                boolean startFromZero = restart || !mRunning ||
+                boolean startFromZero = restart || (!mRunning && !mAnimationState.mOneShot) ||
                         mCurFrame >= mAnimationState.getChildCount();
                 setFrame(startFromZero ? 0 : mCurFrame, true, mAnimating);
             }
@@ -131,7 +133,7 @@
     }
 
     /**
-     * Starts the animation, looping if necessary. This method has no effect
+     * Starts the animation from the first frame, looping if necessary. This method has no effect
      * if the animation is running.
      * <p>
      * <strong>Note:</strong> Do not call this in the
@@ -158,7 +160,7 @@
     }
 
     /**
-     * Stops the animation. This method has no effect if the animation is not
+     * Stops the animation at the current frame. This method has no effect if the animation is not
      * running.
      *
      * @see #isRunning()
@@ -169,6 +171,7 @@
         mAnimating = false;
 
         if (isRunning()) {
+            mCurFrame = 0;
             unscheduleSelf(this);
         }
     }
@@ -196,7 +199,6 @@
 
     @Override
     public void unscheduleSelf(Runnable what) {
-        mCurFrame = 0;
         mRunning = false;
         super.unscheduleSelf(what);
     }
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 31fccd0..3b92507 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -52,8 +52,6 @@
     public static final int HORIZONTAL = 1;
     public static final int VERTICAL = 2;
 
-    private static final int MAX_LEVEL = 10000;
-
     private final Rect mTmpRect = new Rect();
 
     private ClipState mState;
@@ -143,7 +141,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         super.onLevelChange(level);
         invalidateSelf();
         return true;
@@ -153,12 +151,12 @@
     public int getOpacity() {
         final Drawable dr = getDrawable();
         final int opacity = dr.getOpacity();
-        if (opacity == PixelFormat.TRANSPARENT || dr.getLevel() == 0) {
+        if (opacity == PixelFormat.TRANSPARENT || dr.getLevelFloat() == 0) {
             return PixelFormat.TRANSPARENT;
         }
 
-        final int level = getLevel();
-        if (level >= MAX_LEVEL) {
+        final float level = getLevelFloat();
+        if (level >= MAX_LEVEL_FLOAT) {
             return dr.getOpacity();
         }
 
@@ -169,24 +167,24 @@
     @Override
     public void draw(Canvas canvas) {
         final Drawable dr = getDrawable();
-        if (dr.getLevel() == 0) {
+        if (dr.getLevelFloat() == 0) {
             return;
         }
 
         final Rect r = mTmpRect;
         final Rect bounds = getBounds();
-        final int level = getLevel();
+        final float level = getLevelFloat();
 
         int w = bounds.width();
-        final int iw = 0; //mState.mDrawable.getIntrinsicWidth();
+        final int iw = 0;
         if ((mState.mOrientation & HORIZONTAL) != 0) {
-            w -= (w - iw) * (MAX_LEVEL - level) / MAX_LEVEL;
+            w -= Math.round((w - iw) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
         }
 
         int h = bounds.height();
-        final int ih = 0; //mState.mDrawable.getIntrinsicHeight();
+        final int ih = 0;
         if ((mState.mOrientation & VERTICAL) != 0) {
-            h -= (h - ih) * (MAX_LEVEL - level) / MAX_LEVEL;
+            h -= Math.round((h - ih) * (MAX_LEVEL_FLOAT - level) / MAX_LEVEL_FLOAT);
         }
 
         final int layoutDirection = getLayoutDirection();
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index b95c183..fb77155 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -41,6 +41,7 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.FloatProperty;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
@@ -126,12 +127,19 @@
  * document.</p></div>
  */
 public abstract class Drawable {
+
     private static final Rect ZERO_BOUNDS_RECT = new Rect();
 
     static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
 
+    /** The standard maximum value for calls to {@link #setLevel(int)}. */
+    public static final int MAX_LEVEL = 10000;
+
+    /** The standard maximum value for calls to {@link #setLevel(float)}. */
+    public static final float MAX_LEVEL_FLOAT = 10000.0f;
+
     private int[] mStateSet = StateSet.WILD_CARD;
-    private int mLevel = 0;
+    private float mLevel = 0.0f;
     private int mChangingConfigurations = 0;
     private Rect mBounds = ZERO_BOUNDS_RECT;  // lazily becomes a new Rect()
     private WeakReference<Callback> mCallback = null;
@@ -711,22 +719,63 @@
     }
 
     /**
-     * Specify the level for the drawable.  This allows a drawable to vary its
-     * imagery based on a continuous controller, for example to show progress
-     * or volume level.
+     * Sets the level for the drawable as an integer value where typically the
+     * minimum level is 0 and the maximum is 10000 {@link #MAX_LEVEL}; however,
+     * the range may vary based on the Drawable implementation and is not
+     * clamped.
+     * <p>
+     * This allows a drawable to vary its imagery based on a continuous
+     * controller. For example, it may be used to show progress or volume
+     * level.
+     * <p>
+     * Use #setLevelFloat(float) to set the level as a high-precision
+     * floating-point value.
      *
-     * <p>If the new level you are supplying causes the appearance of the
-     * Drawable to change, then it is responsible for calling
-     * {@link #invalidateSelf} in order to have itself redrawn, <em>and</em>
-     * true will be returned from this function.
-     *
-     * @param level The new level, from 0 (minimum) to 10000 (maximum).
-     *
-     * @return Returns true if this change in level has caused the appearance
-     * of the Drawable to change (hence requiring an invalidate), otherwise
-     * returns false.
+     * @param level the new level, typically between 0 and 10000
+     * @return {@code true} if this change in level has caused the appearance
+     *         of the drawable to change and will require a subsequent call to
+     *         invalidate, {@code false} otherwise
+     * @see #getLevel()
+     * @see #setLevel(float)
+     * @see #onLevelChange(int)
      */
     public final boolean setLevel(int level) {
+        return setLevel((float) level);
+    }
+
+    /**
+     * Returns the current level as a rounded integer value.
+     * <p>
+     * Use #getLevelFloat() to return the level as a high-precision
+     * floating-point value.
+     *
+     * @return the current level, typically between 0 and 10000
+     * @see #setLevel(int)
+     * @see #getLevelFloat()
+     */
+    public final int getLevel() {
+        return Math.round(mLevel);
+    }
+
+    /**
+     * Sets the level for the drawable as a floating-point value where
+     * typically the minimum level is 0.0 and the maximum is 10000.0
+     * {@link #MAX_LEVEL_FLOAT}; however, the range may vary based on the
+     * Drawable implementation and is not clamped.
+     * <p>
+     * This allows a drawable to vary its imagery based on a continuous
+     * controller. For example, it may be used to show progress or volume
+     * level.
+     *
+     * @param level the new level, typically between 0.0 and 10000.0
+     *              ({@link #MAX_LEVEL_FLOAT})
+     * @return {@code true} if this change in level has caused the appearance
+     *         of the drawable to change and will require a subsequent call to
+     *         invalidate, {@code false} otherwise
+     * @see #getLevelFloat()
+     * @see #onLevelChange(float)
+     */
+    public final boolean setLevel(float level) {
         if (mLevel != level) {
             mLevel = level;
             return onLevelChange(level);
@@ -735,11 +784,13 @@
     }
 
     /**
-     * Retrieve the current level.
+     * Returns the current level as a floating-point value.
      *
-     * @return int Current level, from 0 (minimum) to 10000 (maximum).
+     * @return the current level, typically between 0.0 and 10000.0
+     *         ({@link #MAX_LEVEL_FLOAT})
+     * @see #setLevel(float)
      */
-    public final int getLevel() {
+    public final float getLevelFloat() {
         return mLevel;
     }
 
@@ -894,14 +945,47 @@
      * last state.
      */
     protected boolean onStateChange(int[] state) { return false; }
-    /** Override this in your subclass to change appearance if you vary based
-     *  on level.
-     * @return Returns true if the level change has caused the appearance of
-     * the Drawable to change (that is, it needs to be drawn), else false
-     * if it looks the same and there is no need to redraw it since its
-     * last level.
+
+    /**
+     * Called when the drawable level changes.
+     * <p>
+     * Override this in your subclass to change appearance if you vary based on
+     * level and do not need floating-point accuracy. To handle changes with
+     * higher accuracy, override {@link #onLevelChange(float)} instead.
+     * <p>
+     * <strong>Note:</strong> Do not override both this method and
+     * {@link #onLevelChange(float)}. Only override one method.
+     *
+     * @param level the level as an integer value, typically between 0
+     *              (minimum) and 10000 ({@link #MAX_LEVEL})
+     * @return {@code true} if the level change has caused the appearance of
+     *         the drawable to change such that it needs to be redrawn, or
+     *         {@code false} if there is no need to redraw
      */
     protected boolean onLevelChange(int level) { return false; }
+
+    /**
+     * Called when the drawable level changes.
+     * <p>
+     * Override this in your subclass to change appearance if you vary based on
+     * level and need floating-point accuracy.
+     * <p>
+     * <strong>Note:</strong> Do not override both this method and
+     * {@link #onLevelChange(int)}. Only override one method. If your app
+     * targets SDK <= 23 ({@link android.os.Build.VERSION_CODES#M M}), you
+     * will need to override {@link #onLevelChange(int)} to receive callbacks
+     * on devices running Android M and below.
+     *
+     * @param level the level as a floating-point value, typically between 0.0
+     *              and 10000.0 ({@link #MAX_LEVEL_FLOAT})
+     * @return {@code true} if the level change has caused the appearance of
+     *         the drawable to change such that it needs to be redrawn, or
+     *         {@code false} if there is no need to redraw
+     */
+    protected boolean onLevelChange(float level) {
+        return onLevelChange(Math.round(level));
+    }
+
     /**
      * Override this in your subclass to change appearance if you vary based on
      * the bounds.
@@ -1328,6 +1412,23 @@
     }
 
     /**
+     * Animatable property for Drawable level.
+     *
+     * @hide Until Drawable animations have been cleaned up.
+     */
+    public static final FloatProperty<Drawable> LEVEL = new FloatProperty<Drawable>("levelFloat") {
+        @Override
+        public Float get(Drawable object) {
+            return object.getLevelFloat();
+        }
+
+        @Override
+        public void setValue(Drawable object, float value) {
+            object.setLevel(value);
+        }
+    };
+
+    /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
      */
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 1915dd7..0210ddb 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -322,7 +322,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         if (mLastDrawable != null) {
             return mLastDrawable.setLevel(level);
         }
@@ -510,7 +510,7 @@
         d.setVisible(isVisible(), true);
         d.setDither(mDrawableContainerState.mDither);
         d.setState(getState());
-        d.setLevel(getLevel());
+        d.setLevel(getLevelFloat());
         d.setBounds(getBounds());
         d.setLayoutDirection(getLayoutDirection());
         d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
index 20d54ca..348af70d 100644
--- a/graphics/java/android/graphics/drawable/DrawableInflater.java
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -112,6 +112,17 @@
     public Drawable inflateFromXml(@NonNull String name, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
+        // Inner classes must be referenced as Outer$Inner, but XML tag names
+        // can't contain $, so the <drawable> tag allows developers to specify
+        // the class in an attribute. We'll still run it through inflateFromTag
+        // to stay consistent with how LayoutInflater works.
+        if (name.equals("drawable")) {
+            name = attrs.getAttributeValue(null, "class");
+            if (name == null) {
+                throw new InflateException("<drawable> tag must specify class attribute");
+            }
+        }
+
         Drawable drawable = inflateFromTag(name);
         if (drawable == null) {
             drawable = inflateFromClass(name);
@@ -192,7 +203,10 @@
             throw ie;
         } catch (ClassNotFoundException e) {
             // If loadClass fails, we should propagate the exception.
-            throw new InflateException("Class not found " + className);
+            final InflateException ie = new InflateException(
+                    "Class not found " + className);
+            ie.initCause(e);
+            throw ie;
         } catch (Exception e) {
             final InflateException ie = new InflateException(
                     "Error inflating class " + className);
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 9185e1a..57b4db2 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -92,7 +92,7 @@
             // Only call setters for data that's stored in the base Drawable.
             dr.setVisible(isVisible(), true);
             dr.setState(getState());
-            dr.setLevel(getLevel());
+            dr.setLevel(getLevelFloat());
             dr.setBounds(getBounds());
             dr.setLayoutDirection(getLayoutDirection());
 
@@ -286,7 +286,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         return mDrawable != null && mDrawable.setLevel(level);
     }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index d7fd8a5..15295a0 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -530,8 +530,8 @@
      *                 {@code false} otherwise
      *
      * @see #mutate()
-     * @see #setLevel(int)
-     * @see #getLevel()
+     * @see #setLevel(float)
+     * @see #getLevelFloat()
      * @see #isUseLevel()
      */
     public void setUseLevel(boolean useLevel) {
@@ -764,7 +764,7 @@
         if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
         mPathIsDirty = false;
 
-        float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
+        float sweep = st.mUseLevelForShape ? (360.0f * getLevelFloat() / MAX_LEVEL_FLOAT) : 360f;
 
         RectF bounds = new RectF(mRect);
 
@@ -990,7 +990,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         super.onLevelChange(level);
         mGradientIsDirty = true;
         mPathIsDirty = true;
@@ -1026,7 +1026,7 @@
                 final float x0, x1, y0, y1;
 
                 if (st.mGradient == LINEAR_GRADIENT) {
-                    final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f;
+                    final float level = st.mUseLevel ? getLevelFloat() / MAX_LEVEL_FLOAT : 1.0f;
                     switch (st.mOrientation) {
                     case TOP_BOTTOM:
                         x0 = r.left;            y0 = r.top;
@@ -1080,7 +1080,7 @@
                     }
 
                     if (st.mUseLevel) {
-                        radius *= getLevel() / 10000.0f;
+                        radius *= getLevelFloat() / MAX_LEVEL_FLOAT;
                     }
 
                     mGradientRadius = radius;
@@ -1115,7 +1115,7 @@
                             tempPositions = st.mTempPositions = new float[length + 1];
                         }
 
-                        final float level = getLevel() / 10000.0f;
+                        final float level = getLevelFloat() / MAX_LEVEL_FLOAT;
                         for (int i = 0; i < length; i++) {
                             tempPositions[i] = i * fraction * level;
                         }
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index d9469d4..c9e38b9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -1366,6 +1366,14 @@
     }
 
     @Override
+    public void jumpToCurrentState() {
+        final ChildDrawable[] children = mLayerState.mChildren;
+        for (int i = 0, count = mLayerState.mNum; i < count; i++) {
+            children[i].mDrawable.jumpToCurrentState();
+        }
+    }
+
+    @Override
     public boolean isStateful() {
         return mLayerState.isStateful();
     }
@@ -1392,7 +1400,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         boolean changed = false;
 
         final ChildDrawable[] array = mLayerState.mChildren;
@@ -1725,7 +1733,7 @@
                 clone.setCallback(owner);
                 clone.setLayoutDirection(dr.getLayoutDirection());
                 clone.setBounds(dr.getBounds());
-                clone.setLevel(dr.getLevel());
+                clone.setLevel(dr.getLevelFloat());
             } else {
                 clone = null;
             }
diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java
index b01c643..09d8b6f 100644
--- a/graphics/java/android/graphics/drawable/LevelListDrawable.java
+++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java
@@ -69,15 +69,16 @@
         if (drawable != null) {
             mLevelListState.addLevel(low, high, drawable);
             // in case the new state matches our current state...
-            onLevelChange(getLevel());
+            onLevelChange(getLevelFloat());
         }
     }
 
     // overrides from Drawable
 
     @Override
-    protected boolean onLevelChange(int level) {
-        int idx = mLevelListState.indexOfLevel(level);
+    protected boolean onLevelChange(float level) {
+        final int nearestLevel = Math.round(level);
+        final int idx = mLevelListState.indexOfLevel(nearestLevel);
         if (selectDrawable(idx)) {
             return true;
         }
@@ -141,7 +142,7 @@
             mLevelListState.addLevel(low, high, dr);
         }
 
-        onLevelChange(getLevel());
+        onLevelChange(getLevelFloat());
     }
 
     @Override
@@ -240,7 +241,7 @@
     private LevelListDrawable(LevelListState state, Resources res) {
         final LevelListState as = new LevelListState(state, this, res);
         setConstantState(as);
-        onLevelChange(getLevel());
+        onLevelChange(getLevelFloat());
     }
 }
 
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 036a078..71c9977 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -303,10 +303,10 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         super.onLevelChange(level);
 
-        final float value = level / (float) MAX_LEVEL;
+        final float value = level / (float) MAX_LEVEL_FLOAT;
         final float degrees = MathUtils.lerp(mState.mFromDegrees, mState.mToDegrees, value);
         mState.mCurrentDegrees = degrees;
 
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index 0acbeda..38c6b80 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -50,8 +50,6 @@
  * @attr ref android.R.styleable#ScaleDrawable_drawable
  */
 public class ScaleDrawable extends DrawableWrapper {
-    private static final int MAX_LEVEL = 10000;
-
     private final Rect mTmpRect = new Rect();
 
     private ScaleState mState;
@@ -170,7 +168,7 @@
     @Override
     public void draw(Canvas canvas) {
         final Drawable d = getDrawable();
-        if (d != null && d.getLevel() != 0) {
+        if (d != null && d.getLevelFloat() != 0) {
             d.draw(canvas);
         }
     }
@@ -178,12 +176,12 @@
     @Override
     public int getOpacity() {
         final Drawable d = getDrawable();
-        if (d.getLevel() == 0) {
+        if (d.getLevelFloat() == 0) {
             return PixelFormat.TRANSPARENT;
         }
 
         final int opacity = d.getOpacity();
-        if (opacity == PixelFormat.OPAQUE && d.getLevel() < MAX_LEVEL) {
+        if (opacity == PixelFormat.OPAQUE && d.getLevelFloat() < MAX_LEVEL_FLOAT) {
             return PixelFormat.TRANSLUCENT;
         }
 
@@ -191,7 +189,7 @@
     }
 
     @Override
-    protected boolean onLevelChange(int level) {
+    protected boolean onLevelChange(float level) {
         super.onLevelChange(level);
         onBoundsChange(getBounds());
         invalidateSelf();
@@ -203,18 +201,20 @@
         final Drawable d = getDrawable();
         final Rect r = mTmpRect;
         final boolean min = mState.mUseIntrinsicSizeAsMin;
-        final int level = getLevel();
+        final float level = getLevelFloat();
 
         int w = bounds.width();
         if (mState.mScaleWidth > 0) {
             final int iw = min ? d.getIntrinsicWidth() : 0;
-            w -= (int) ((w - iw) * (MAX_LEVEL - level) * mState.mScaleWidth / MAX_LEVEL);
+            w -= (int) ((w - iw) * (MAX_LEVEL_FLOAT - level)
+                    * mState.mScaleWidth / MAX_LEVEL_FLOAT);
         }
 
         int h = bounds.height();
         if (mState.mScaleHeight > 0) {
             final int ih = min ? d.getIntrinsicHeight() : 0;
-            h -= (int) ((h - ih) * (MAX_LEVEL - level) * mState.mScaleHeight / MAX_LEVEL);
+            h -= (int) ((h - ih) * (MAX_LEVEL_FLOAT - level)
+                    * mState.mScaleHeight / MAX_LEVEL_FLOAT);
         }
 
         final int layoutDirection = getLayoutDirection();
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 1cfccc4..1747225 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -726,7 +726,7 @@
         Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
         // Then print all the children groups
         for (int i = 0; i < currentGroup.mChildren.size(); i++) {
-            Object child = currentGroup.mChildren.get(i);
+            final VObject child = currentGroup.mChildren.get(i);
             if (child instanceof VGroup) {
                 printGroupTree((VGroup) child, level + 1);
             }
@@ -783,12 +783,6 @@
                 mThemeAttrs = copy.mThemeAttrs;
                 mChangingConfigurations = copy.mChangingConfigurations;
                 mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
-                if (copy.mVPathRenderer.mFillPaint != null) {
-                    mVPathRenderer.mFillPaint = new Paint(copy.mVPathRenderer.mFillPaint);
-                }
-                if (copy.mVPathRenderer.mStrokePaint != null) {
-                    mVPathRenderer.mStrokePaint = new Paint(copy.mVPathRenderer.mStrokePaint);
-                }
                 mTint = copy.mTint;
                 mTintMode = copy.mTintMode;
                 mAutoMirrored = copy.mAutoMirrored;
@@ -913,13 +907,7 @@
          */
         // Variables that only used temporarily inside the draw() call, so there
         // is no need for deep copying.
-        private final Path mPath;
-        private final Path mRenderPath;
-        private final Matrix mFinalPathMatrix = new Matrix();
-
-        private Paint mStrokePaint;
-        private Paint mFillPaint;
-        private PathMeasure mPathMeasure;
+        private final TempState mTempState = new TempState();
 
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
@@ -935,12 +923,10 @@
 
         int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
 
-        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+        final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<>();
 
         public VPathRenderer() {
             mRootGroup = new VGroup();
-            mPath = new Path();
-            mRenderPath = new Path();
         }
 
         public void setRootAlpha(int alpha) {
@@ -964,8 +950,6 @@
 
         public VPathRenderer(VPathRenderer copy) {
             mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
-            mPath = new Path(copy.mPath);
-            mRenderPath = new Path(copy.mRenderPath);
             mBaseWidth = copy.mBaseWidth;
             mBaseHeight = copy.mBaseHeight;
             mViewportWidth = copy.mViewportWidth;
@@ -981,215 +965,28 @@
         }
 
         public boolean canApplyTheme() {
-            // If one of the paths can apply theme, then return true;
-            return recursiveCanApplyTheme(mRootGroup);
-        }
-
-        private boolean recursiveCanApplyTheme(VGroup currentGroup) {
-            // We can do a tree traverse here, if there is one path return true,
-            // then we return true for the whole tree.
-            final ArrayList<Object> children = currentGroup.mChildren;
-
-            for (int i = 0; i < children.size(); i++) {
-                Object child = children.get(i);
-                if (child instanceof VGroup) {
-                    VGroup childGroup = (VGroup) child;
-                    if (childGroup.canApplyTheme()
-                            || recursiveCanApplyTheme(childGroup)) {
-                        return true;
-                    }
-                } else if (child instanceof VPath) {
-                    VPath childPath = (VPath) child;
-                    if (childPath.canApplyTheme()) {
-                        return true;
-                    }
-                }
-            }
-            return false;
+            return mRootGroup.canApplyTheme();
         }
 
         public void applyTheme(Theme t) {
-            // Apply theme to every path of the tree.
-            recursiveApplyTheme(mRootGroup, t);
-        }
-
-        private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
-            // We can do a tree traverse here, apply theme to all paths which
-            // can apply theme.
-            final ArrayList<Object> children = currentGroup.mChildren;
-            for (int i = 0; i < children.size(); i++) {
-                Object child = children.get(i);
-                if (child instanceof VGroup) {
-                    VGroup childGroup = (VGroup) child;
-                    if (childGroup.canApplyTheme()) {
-                        childGroup.applyTheme(t);
-                    }
-                    recursiveApplyTheme(childGroup, t);
-                } else if (child instanceof VPath) {
-                    VPath childPath = (VPath) child;
-                    if (childPath.canApplyTheme()) {
-                        childPath.applyTheme(t);
-                    }
-                }
-            }
-        }
-
-        private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
-                Canvas canvas, int w, int h, ColorFilter filter) {
-            // Calculate current group's matrix by preConcat the parent's and
-            // and the current one on the top of the stack.
-            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
-            // Mi the local matrix at level i of the group tree.
-            currentGroup.mStackedMatrix.set(currentMatrix);
-            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
-
-            // Save the current clip information, which is local to this group.
-            canvas.save();
-            // Draw the group tree in the same order as the XML file.
-            for (int i = 0; i < currentGroup.mChildren.size(); i++) {
-                Object child = currentGroup.mChildren.get(i);
-                if (child instanceof VGroup) {
-                    VGroup childGroup = (VGroup) child;
-                    drawGroupTree(childGroup, currentGroup.mStackedMatrix,
-                            canvas, w, h, filter);
-                } else if (child instanceof VPath) {
-                    VPath childPath = (VPath) child;
-                    drawPath(currentGroup, childPath, canvas, w, h, filter);
-                }
-            }
-            canvas.restore();
+            mRootGroup.applyTheme(t);
         }
 
         public void draw(Canvas canvas, int w, int h, ColorFilter filter) {
-            // Travese the tree in pre-order to draw.
-            drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvas, w, h, filter);
-        }
-
-        private void drawPath(VGroup vGroup, VPath vPath, Canvas canvas, int w, int h,
-                ColorFilter filter) {
             final float scaleX = w / mViewportWidth;
             final float scaleY = h / mViewportHeight;
-            final float minScale = Math.min(scaleX, scaleY);
-            final Matrix groupStackedMatrix = vGroup.mStackedMatrix;
-
-            mFinalPathMatrix.set(groupStackedMatrix);
-            mFinalPathMatrix.postScale(scaleX, scaleY);
-
-            final float matrixScale = getMatrixScale(groupStackedMatrix);
-            if (matrixScale == 0) {
-                // When either x or y is scaled to 0, we don't need to draw anything.
-                return;
-            }
-            vPath.toPath(mPath);
-            final Path path = mPath;
-
-            mRenderPath.reset();
-
-            if (vPath.isClipPath()) {
-                mRenderPath.addPath(path, mFinalPathMatrix);
-                canvas.clipPath(mRenderPath);
-            } else {
-                VFullPath fullPath = (VFullPath) vPath;
-                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
-                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
-                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
-
-                    if (mPathMeasure == null) {
-                        mPathMeasure = new PathMeasure();
-                    }
-                    mPathMeasure.setPath(mPath, false);
-
-                    float len = mPathMeasure.getLength();
-                    start = start * len;
-                    end = end * len;
-                    path.reset();
-                    if (start > end) {
-                        mPathMeasure.getSegment(start, len, path, true);
-                        mPathMeasure.getSegment(0f, end, path, true);
-                    } else {
-                        mPathMeasure.getSegment(start, end, path, true);
-                    }
-                    path.rLineTo(0, 0); // fix bug in measure
-                }
-                mRenderPath.addPath(path, mFinalPathMatrix);
-
-                if (fullPath.mFillColor != Color.TRANSPARENT) {
-                    if (mFillPaint == null) {
-                        mFillPaint = new Paint();
-                        mFillPaint.setStyle(Paint.Style.FILL);
-                        mFillPaint.setAntiAlias(true);
-                    }
-
-                    final Paint fillPaint = mFillPaint;
-                    fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
-                    fillPaint.setColorFilter(filter);
-                    canvas.drawPath(mRenderPath, fillPaint);
-                }
-
-                if (fullPath.mStrokeColor != Color.TRANSPARENT) {
-                    if (mStrokePaint == null) {
-                        mStrokePaint = new Paint();
-                        mStrokePaint.setStyle(Paint.Style.STROKE);
-                        mStrokePaint.setAntiAlias(true);
-                    }
-
-                    final Paint strokePaint = mStrokePaint;
-                    if (fullPath.mStrokeLineJoin != null) {
-                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
-                    }
-
-                    if (fullPath.mStrokeLineCap != null) {
-                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
-                    }
-
-                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
-                    strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
-                    strokePaint.setColorFilter(filter);
-                    final float finalStrokeScale = minScale * matrixScale;
-                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
-                    canvas.drawPath(mRenderPath, strokePaint);
-                }
-            }
-        }
-
-        private float getMatrixScale(Matrix groupStackedMatrix) {
-            // Given unit vectors A = (0, 1) and B = (1, 0).
-            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
-            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
-            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
-            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
-            //
-            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
-            // scale on x and y axis, and take the minimal of these two.
-            // For skew case, an unit square will mapped to a parallelogram. And this function will
-            // return the minimal height of the 2 bases.
-            float[] unitVectors = new float[] {0, 1, 1, 0};
-            groupStackedMatrix.mapVectors(unitVectors);
-            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
-            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
-            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
-                    unitVectors[2], unitVectors[3]);
-            float maxScale = MathUtils.max(scaleX, scaleY);
-
-            float matrixScale = 0;
-            if (maxScale > 0) {
-                matrixScale = MathUtils.abs(crossProduct) / maxScale;
-            }
-            if (DBG_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
-            }
-            return matrixScale;
+            mRootGroup.draw(canvas, mTempState, Matrix.IDENTITY_MATRIX, filter, scaleX, scaleY);
         }
     }
 
-    private static class VGroup {
+    private static class VGroup implements VObject {
         // mStackedMatrix is only used temporarily when drawing, it combines all
         // the parents' local matrices with the current one.
         private final Matrix mStackedMatrix = new Matrix();
 
         /////////////////////////////////////////////////////
         // Variables below need to be copied (deep copy if applicable) for mutation.
-        final ArrayList<Object> mChildren = new ArrayList<Object>();
+        final ArrayList<VObject> mChildren = new ArrayList<>();
 
         private float mRotate = 0;
         private float mPivotX = 0;
@@ -1223,14 +1020,14 @@
 
             mLocalMatrix.set(copy.mLocalMatrix);
 
-            final ArrayList<Object> children = copy.mChildren;
+            final ArrayList<VObject> children = copy.mChildren;
             for (int i = 0; i < children.size(); i++) {
-                Object copyChild = children.get(i);
+                final VObject copyChild = children.get(i);
                 if (copyChild instanceof VGroup) {
-                    VGroup copyGroup = (VGroup) copyChild;
+                    final VGroup copyGroup = (VGroup) copyChild;
                     mChildren.add(new VGroup(copyGroup, targetsMap));
                 } else {
-                    VPath newPath = null;
+                    final VPath newPath;
                     if (copyChild instanceof VFullPath) {
                         newPath = new VFullPath((VFullPath) copyChild);
                     } else if (copyChild instanceof VClipPath) {
@@ -1257,6 +1054,30 @@
             return mLocalMatrix;
         }
 
+        @Override
+        public void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
+                ColorFilter filter, float scaleX, float scaleY) {
+            // Calculate current group's matrix by preConcat the parent's and
+            // and the current one on the top of the stack.
+            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+            // Mi the local matrix at level i of the group tree.
+            mStackedMatrix.set(currentMatrix);
+            mStackedMatrix.preConcat(mLocalMatrix);
+
+            // Save the current clip information, which is local to this group.
+            canvas.save();
+
+            // Draw the group tree in the same order as the XML file.
+            for (int i = 0, count = mChildren.size(); i < count; i++) {
+                final VObject child = mChildren.get(i);
+                child.draw(canvas, temp, mStackedMatrix, filter, scaleX, scaleY);
+            }
+
+            // Restore the previous clip information.
+            canvas.restore();
+        }
+
+        @Override
         public void inflate(Resources res, AttributeSet attrs, Theme theme) {
             final TypedArray a = obtainAttributes(res, theme, attrs,
                     R.styleable.VectorDrawableGroup);
@@ -1287,18 +1108,39 @@
             updateLocalMatrix();
         }
 
+        @Override
         public boolean canApplyTheme() {
-            return mThemeAttrs != null;
-        }
-
-        public void applyTheme(Theme t) {
-            if (mThemeAttrs == null) {
-                return;
+            if (mThemeAttrs != null) {
+                return true;
             }
 
-            final TypedArray a = t.resolveAttributes(mThemeAttrs, R.styleable.VectorDrawableGroup);
-            updateStateFromTypedArray(a);
-            a.recycle();
+            final ArrayList<VObject> children = mChildren;
+            for (int i = 0, count = children.size(); i < count; i++) {
+                final VObject child = children.get(i);
+                if (child.canApplyTheme()) {
+                    return true;
+                }
+            }
+
+            return false;
+        }
+
+        @Override
+        public void applyTheme(Theme t) {
+            if (mThemeAttrs != null) {
+                final TypedArray a = t.resolveAttributes(mThemeAttrs,
+                        R.styleable.VectorDrawableGroup);
+                updateStateFromTypedArray(a);
+                a.recycle();
+            }
+
+            final ArrayList<VObject> children = mChildren;
+            for (int i = 0, count = children.size(); i < count; i++) {
+                final VObject child = children.get(i);
+                if (child.canApplyTheme()) {
+                    child.applyTheme(t);
+                }
+            }
         }
 
         private void updateLocalMatrix() {
@@ -1407,7 +1249,7 @@
     /**
      * Common Path information for clip path and normal path.
      */
-    private static class VPath {
+    private static abstract class VPath implements VObject {
         protected PathParser.PathDataNode[] mNodes = null;
         String mPathName;
         int mChangingConfigurations;
@@ -1422,24 +1264,10 @@
             mNodes = PathParser.deepCopyNodes(copy.mNodes);
         }
 
-        public void toPath(Path path) {
-            path.reset();
-            if (mNodes != null) {
-                PathParser.PathDataNode.nodesToPath(mNodes, path);
-            }
-        }
-
         public String getPathName() {
             return mPathName;
         }
 
-        public boolean canApplyTheme() {
-            return false;
-        }
-
-        public void applyTheme(Theme t) {
-        }
-
         public boolean isClipPath() {
             return false;
         }
@@ -1459,6 +1287,79 @@
                 PathParser.updateNodes(mNodes, nodes);
             }
         }
+
+        @Override
+        public final void draw(Canvas canvas, TempState temp, Matrix groupStackedMatrix,
+                ColorFilter filter, float scaleX, float scaleY) {
+            final float matrixScale = VPath.getMatrixScale(groupStackedMatrix);
+            if (matrixScale == 0) {
+                // When either x or y is scaled to 0, we don't need to draw anything.
+                return;
+            }
+
+            final Path path = temp.path;
+            path.reset();
+            toPath(temp, path);
+
+            final Matrix pathMatrix = temp.pathMatrix;
+            pathMatrix.set(groupStackedMatrix);
+            pathMatrix.postScale(scaleX, scaleY);
+
+            final Path renderPath = temp.renderPath;
+            renderPath.reset();
+            renderPath.addPath(path, pathMatrix);
+
+            final float minScale = Math.min(scaleX, scaleY);
+            final float strokeScale = minScale * matrixScale;
+            drawPath(temp, renderPath, canvas, filter, strokeScale);
+        }
+
+        /**
+         * Writes the path's nodes to an output Path for rendering.
+         *
+         * @param temp temporary state variables
+         * @param outPath the output path
+         */
+        protected void toPath(TempState temp, Path outPath) {
+            if (mNodes != null) {
+                PathParser.PathDataNode.nodesToPath(mNodes, outPath);
+            }
+        }
+
+        /**
+         * Draws the specified path into the supplied canvas.
+         */
+        protected abstract void drawPath(TempState temp, Path path, Canvas canvas,
+                ColorFilter filter, float strokeScale);
+
+        private static float getMatrixScale(Matrix groupStackedMatrix) {
+            // Given unit vectors A = (0, 1) and B = (1, 0).
+            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+            //
+            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+            // scale on x and y axis, and take the minimal of these two.
+            // For skew case, an unit square will mapped to a parallelogram. And this function will
+            // return the minimal height of the 2 bases.
+            float[] unitVectors = new float[] {0, 1, 1, 0};
+            groupStackedMatrix.mapVectors(unitVectors);
+            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+                    unitVectors[2], unitVectors[3]);
+            float maxScale = MathUtils.max(scaleX, scaleY);
+
+            float matrixScale = 0;
+            if (maxScale > 0) {
+                matrixScale = MathUtils.abs(crossProduct) / maxScale;
+            }
+            if (DBG_VECTOR_DRAWABLE) {
+                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+            }
+            return matrixScale;
+        }
     }
 
     /**
@@ -1473,6 +1374,13 @@
             super(copy);
         }
 
+        @Override
+        protected void drawPath(TempState temp, Path renderPath, Canvas canvas, ColorFilter filter,
+                float strokeScale) {
+            canvas.clipPath(renderPath);
+        }
+
+        @Override
         public void inflate(Resources r, AttributeSet attrs, Theme theme) {
             final TypedArray a = obtainAttributes(r, theme, attrs,
                     R.styleable.VectorDrawableClipPath);
@@ -1480,6 +1388,16 @@
             a.recycle();
         }
 
+        @Override
+        public boolean canApplyTheme() {
+            return false;
+        }
+
+        @Override
+        public void applyTheme(Theme theme) {
+            // No-op.
+        }
+
         private void updateStateFromTypedArray(TypedArray a) {
             // Account for any configuration changes.
             mChangingConfigurations |= a.getChangingConfigurations();
@@ -1574,10 +1492,104 @@
         }
 
         @Override
-        public boolean canApplyTheme() {
-            return mThemeAttrs != null;
+        public void toPath(TempState temp, Path path) {
+            super.toPath(temp, path);
+
+            if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+                VFullPath.applyTrim(temp, path, mTrimPathStart, mTrimPathEnd, mTrimPathOffset);
+            }
         }
 
+        @Override
+        protected void drawPath(TempState temp, Path path, Canvas canvas, ColorFilter filter,
+                float strokeScale) {
+            drawPathFill(temp, path, canvas, filter);
+            drawPathStroke(temp, path, canvas, filter, strokeScale);
+        }
+
+        /**
+         * Draws this path's fill, if necessary.
+         */
+        private void drawPathFill(TempState temp, Path path, Canvas canvas, ColorFilter filter) {
+            if (mFillColor == Color.TRANSPARENT) {
+                return;
+            }
+
+            if (temp.mFillPaint == null) {
+                temp.mFillPaint = new Paint();
+                temp.mFillPaint.setStyle(Paint.Style.FILL);
+                temp.mFillPaint.setAntiAlias(true);
+            }
+
+            final Paint fillPaint = temp.mFillPaint;
+            fillPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+            fillPaint.setColorFilter(filter);
+            canvas.drawPath(path, fillPaint);
+        }
+
+        /**
+         * Draws this path's stroke, if necessary.
+         */
+        private void drawPathStroke(TempState temp, Path path, Canvas canvas, ColorFilter filter,
+                float strokeScale) {
+            if (mStrokeColor == Color.TRANSPARENT) {
+                return;
+            }
+
+            if (temp.mStrokePaint == null) {
+                temp.mStrokePaint = new Paint();
+                temp.mStrokePaint.setStyle(Paint.Style.STROKE);
+                temp.mStrokePaint.setAntiAlias(true);
+            }
+
+            final Paint strokePaint = temp.mStrokePaint;
+            if (mStrokeLineJoin != null) {
+                strokePaint.setStrokeJoin(mStrokeLineJoin);
+            }
+
+            if (mStrokeLineCap != null) {
+                strokePaint.setStrokeCap(mStrokeLineCap);
+            }
+
+            strokePaint.setStrokeMiter(mStrokeMiterlimit);
+            strokePaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+            strokePaint.setColorFilter(filter);
+            strokePaint.setStrokeWidth(mStrokeWidth * strokeScale);
+            canvas.drawPath(path, strokePaint);
+        }
+
+        /**
+         * Applies trimming to the specified path.
+         */
+        private static void applyTrim(TempState temp, Path path, float mTrimPathStart,
+                float mTrimPathEnd, float mTrimPathOffset) {
+            if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+                // No trimming necessary.
+                return;
+            }
+
+            if (temp.mPathMeasure == null) {
+                temp.mPathMeasure = new PathMeasure();
+            }
+            final PathMeasure pathMeasure = temp.mPathMeasure;
+            pathMeasure.setPath(path, false);
+
+            final float len = pathMeasure.getLength();
+            final float start = len * ((mTrimPathStart + mTrimPathOffset) % 1.0f);
+            final float end = len * ((mTrimPathEnd + mTrimPathOffset) % 1.0f);
+            path.reset();
+            if (start > end) {
+                pathMeasure.getSegment(start, len, path, true);
+                pathMeasure.getSegment(0, end, path, true);
+            } else {
+                pathMeasure.getSegment(start, end, path, true);
+            }
+
+            // Fix bug in measure.
+            path.rLineTo(0, 0);
+        }
+
+        @Override
         public void inflate(Resources r, AttributeSet attrs, Theme theme) {
             final TypedArray a = obtainAttributes(r, theme, attrs,
                     R.styleable.VectorDrawablePath);
@@ -1627,6 +1639,11 @@
         }
 
         @Override
+        public boolean canApplyTheme() {
+            return mThemeAttrs != null;
+        }
+
+        @Override
         public void applyTheme(Theme t) {
             if (mThemeAttrs == null) {
                 return;
@@ -1718,4 +1735,22 @@
             mTrimPathOffset = trimPathOffset;
         }
     }
+
+    static class TempState {
+        final Matrix pathMatrix = new Matrix();
+        final Path path = new Path();
+        final Path renderPath = new Path();
+
+        PathMeasure mPathMeasure;
+        Paint mFillPaint;
+        Paint mStrokePaint;
+    }
+
+    interface VObject {
+        void draw(Canvas canvas, TempState temp, Matrix currentMatrix,
+                ColorFilter filter, float scaleX, float scaleY);
+        void inflate(Resources r, AttributeSet attrs, Theme theme);
+        boolean canApplyTheme();
+        void applyTheme(Theme t);
+    }
 }
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index 2f28700..f682fb8 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -40,10 +40,9 @@
 # For the host
 # =====================================================
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_HOST_OS := darwin linux windows
 LOCAL_CFLAGS += -DSTATIC_ANDROIDFW_FOR_TOOLS
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 LOCAL_SRC_FILES:= $(hostSources)
@@ -56,13 +55,10 @@
 # =====================================================
 
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE:= libandroidfw
-LOCAL_MODULE_TAGS := optional
 LOCAL_SRC_FILES:= $(deviceSources)
 LOCAL_C_INCLUDES := \
-    external/zlib \
     system/core/include
 LOCAL_STATIC_LIBRARIES := libziparchive libbase
 LOCAL_SHARED_LIBRARIES := \
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index b3b3479..3eb13ab 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -75,7 +75,8 @@
     TessellationCache.cpp \
     TextDropShadowCache.cpp \
     Texture.cpp \
-    TextureCache.cpp
+    TextureCache.cpp \
+    protos/hwui.proto
 
 hwui_cflags := \
     -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES \
@@ -92,6 +93,12 @@
     hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
 endif
 
+# This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
+# which varies depending on what is being built
+define hwui_proto_include
+$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
+endef
+
 hwui_c_includes += \
     external/skia/src/core
 
@@ -104,6 +111,7 @@
     libskia \
     libui \
     libgui \
+    libprotobuf-cpp-lite \
 
 ifneq (false,$(ANDROID_ENABLE_RENDERSCRIPT))
     hwui_cflags += -DANDROID_ENABLE_RENDERSCRIPT
@@ -126,7 +134,8 @@
 LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := $(hwui_cflags)
 LOCAL_SRC_FILES := $(hwui_src_files)
-LOCAL_C_INCLUDES := $(hwui_c_includes)
+LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(hwui_c_includes) $(call hwui_proto_include)
 
 include $(BUILD_STATIC_LIBRARY)
 
@@ -153,10 +162,10 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_STATIC_LIBRARIES := libhwui_static
-LOCAL_C_INCLUDES := $(hwui_c_includes)
 LOCAL_CFLAGS := $(hwui_cflags)
 
 LOCAL_SRC_FILES += \
+    unit_tests/CanvasStateTests.cpp \
     unit_tests/ClipAreaTests.cpp \
     unit_tests/DamageAccumulatorTests.cpp \
     unit_tests/LinearAllocatorTests.cpp
@@ -172,16 +181,20 @@
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
 LOCAL_MODULE:= hwuitest
 LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_CLASS := EXECUTABLES
 LOCAL_MULTILIB := both
 LOCAL_MODULE_STEM_32 := hwuitest
 LOCAL_MODULE_STEM_64 := hwuitest64
 LOCAL_SHARED_LIBRARIES := $(hwui_shared_libraries)
 LOCAL_CFLAGS := $(hwui_cflags)
-LOCAL_C_INCLUDES := $(hwui_c_includes)
 
 HWUI_NULL_GPU := false
 
 ifeq (true, $(HWUI_NULL_GPU))
+    # Only need to specify the includes if we are not linking against
+    # libhwui_static as libhwui_static exports the appropriate includes
+    LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
+
     LOCAL_SRC_FILES := \
         $(hwui_src_files) \
         tests/nullegl.cpp \
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 4bd4ae1..922ff7c 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,6 +26,13 @@
 
 class Outline {
 public:
+    enum class Type {
+        None = 0,
+        Empty = 1,
+        ConvexPath = 2,
+        RoundRect = 3
+    };
+
     Outline()
             : mShouldClip(false)
             , mType(Type::None)
@@ -122,14 +129,19 @@
         return &mPath;
     }
 
-private:
-    enum class Type {
-        None = 0,
-        Empty = 1,
-        ConvexPath = 2,
-        RoundRect = 3
-    };
+    Type getType() const {
+        return mType;
+    }
 
+    const Rect& getBounds() const {
+        return mBounds;
+    }
+
+    float getRadius() const {
+        return mRadius;
+    }
+
+private:
     bool mShouldClip;
     Type mType;
     Rect mBounds;
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 7d09c0b..ddc7ecd 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -33,6 +33,9 @@
 #include "utils/TraceUtils.h"
 #include "renderthread/CanvasContext.h"
 
+#include "protos/hwui.pb.h"
+#include "protos/ProtoHelpers.h"
+
 namespace android {
 namespace uirenderer {
 
@@ -102,6 +105,78 @@
     ALOGD("%*sDone (%p, %s)", (level - 1) * 2, "", this, getName());
 }
 
+void RenderNode::copyTo(proto::RenderNode *pnode) {
+    pnode->set_id(static_cast<uint64_t>(
+            reinterpret_cast<uintptr_t>(this)));
+    pnode->set_name(mName.string(), mName.length());
+
+    proto::RenderProperties* pprops = pnode->mutable_properties();
+    pprops->set_left(properties().getLeft());
+    pprops->set_top(properties().getTop());
+    pprops->set_right(properties().getRight());
+    pprops->set_bottom(properties().getBottom());
+    pprops->set_clip_flags(properties().getClippingFlags());
+    pprops->set_alpha(properties().getAlpha());
+    pprops->set_translation_x(properties().getTranslationX());
+    pprops->set_translation_y(properties().getTranslationY());
+    pprops->set_translation_z(properties().getTranslationZ());
+    pprops->set_elevation(properties().getElevation());
+    pprops->set_rotation(properties().getRotation());
+    pprops->set_rotation_x(properties().getRotationX());
+    pprops->set_rotation_y(properties().getRotationY());
+    pprops->set_scale_x(properties().getScaleX());
+    pprops->set_scale_y(properties().getScaleY());
+    pprops->set_pivot_x(properties().getPivotX());
+    pprops->set_pivot_y(properties().getPivotY());
+    pprops->set_has_overlapping_rendering(properties().getHasOverlappingRendering());
+    pprops->set_pivot_explicitly_set(properties().isPivotExplicitlySet());
+    pprops->set_project_backwards(properties().getProjectBackwards());
+    pprops->set_projection_receiver(properties().isProjectionReceiver());
+    set(pprops->mutable_clip_bounds(), properties().getClipBounds());
+
+    const Outline& outline = properties().getOutline();
+    if (outline.getType() != Outline::Type::None) {
+        proto::Outline* poutline = pprops->mutable_outline();
+        poutline->clear_path();
+        if (outline.getType() == Outline::Type::Empty) {
+            poutline->set_type(proto::Outline_Type_Empty);
+        } else if (outline.getType() == Outline::Type::ConvexPath) {
+            poutline->set_type(proto::Outline_Type_ConvexPath);
+            if (const SkPath* path = outline.getPath()) {
+                set(poutline->mutable_path(), *path);
+            }
+        } else if (outline.getType() == Outline::Type::RoundRect) {
+            poutline->set_type(proto::Outline_Type_RoundRect);
+        } else {
+            ALOGW("Uknown outline type! %d", static_cast<int>(outline.getType()));
+            poutline->set_type(proto::Outline_Type_None);
+        }
+        poutline->set_should_clip(outline.getShouldClip());
+        poutline->set_alpha(outline.getAlpha());
+        poutline->set_radius(outline.getRadius());
+        set(poutline->mutable_bounds(), outline.getBounds());
+    } else {
+        pprops->clear_outline();
+    }
+
+    const RevealClip& revealClip = properties().getRevealClip();
+    if (revealClip.willClip()) {
+        proto::RevealClip* prevealClip = pprops->mutable_reveal_clip();
+        prevealClip->set_x(revealClip.getX());
+        prevealClip->set_y(revealClip.getY());
+        prevealClip->set_radius(revealClip.getRadius());
+    } else {
+        pprops->clear_reveal_clip();
+    }
+
+    pnode->clear_children();
+    if (mDisplayListData) {
+        for (auto&& child : mDisplayListData->children()) {
+            child->mRenderNode->copyTo(pnode->add_children());
+        }
+    }
+}
+
 int RenderNode::getDebugSize() {
     int size = sizeof(RenderNode);
     if (mStagingDisplayListData) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 3bff2b3..88fc608 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -57,6 +57,10 @@
 class DrawRenderNodeOp;
 class TreeInfo;
 
+namespace proto {
+class RenderNode;
+}
+
 /**
  * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
  *
@@ -96,7 +100,6 @@
         kReplayFlag_ClipChildren = 0x1
     };
 
-    static void outputLogBuffer(int fd);
     void debugDumpLayers(const char* prefix);
 
     ANDROID_API void setStagingDisplayList(DisplayListData* newData);
@@ -108,6 +111,7 @@
 
     ANDROID_API void output(uint32_t level = 1);
     ANDROID_API int getDebugSize();
+    void copyTo(proto::RenderNode* node);
 
     bool isRenderable() const {
         return mDisplayListData && !mDisplayListData->isEmpty();
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index a9ae9b5..ad74bff 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -70,23 +70,6 @@
     return *this;
 }
 
-RenderProperties::PrimitiveFields::PrimitiveFields()
-        : mClippingFlags(CLIP_TO_BOUNDS)
-        , mProjectBackwards(false)
-        , mProjectionReceiver(false)
-        , mAlpha(1)
-        , mHasOverlappingRendering(true)
-        , mElevation(0)
-        , mTranslationX(0), mTranslationY(0), mTranslationZ(0)
-        , mRotation(0), mRotationX(0), mRotationY(0)
-        , mScaleX(1), mScaleY(1)
-        , mPivotX(0), mPivotY(0)
-        , mLeft(0), mTop(0), mRight(0), mBottom(0)
-        , mWidth(0), mHeight(0)
-        , mPivotExplicitlySet(false)
-        , mMatrixOrPivotDirty(false) {
-}
-
 RenderProperties::ComputedFields::ComputedFields()
         : mTransformMatrix(nullptr) {
 }
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 11abd70..71589c8 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -417,7 +417,7 @@
         return false;
     }
 
-    float getLeft() const {
+    int getLeft() const {
         return mPrimitiveFields.mLeft;
     }
 
@@ -432,7 +432,7 @@
         return false;
     }
 
-    float getTop() const {
+    int getTop() const {
         return mPrimitiveFields.mTop;
     }
 
@@ -447,7 +447,7 @@
         return false;
     }
 
-    float getRight() const {
+    int getRight() const {
         return mPrimitiveFields.mRight;
     }
 
@@ -462,7 +462,7 @@
         return false;
     }
 
-    float getBottom() const {
+    int getBottom() const {
         return mPrimitiveFields.mBottom;
     }
 
@@ -541,6 +541,10 @@
         return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
     }
 
+    const Rect& getClipBounds() const {
+        return mPrimitiveFields.mClipBounds;
+    }
+
     void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
         if (flags & CLIP_TO_BOUNDS) {
             outRect->set(0, 0, getWidth(), getHeight());
@@ -621,25 +625,23 @@
 private:
     // Rendering properties
     struct PrimitiveFields {
-        PrimitiveFields();
-
+        int mLeft = 0, mTop = 0, mRight = 0, mBottom = 0;
+        int mWidth = 0, mHeight = 0;
+        int mClippingFlags = CLIP_TO_BOUNDS;
+        float mAlpha = 1;
+        float mTranslationX = 0, mTranslationY = 0, mTranslationZ = 0;
+        float mElevation = 0;
+        float mRotation = 0, mRotationX = 0, mRotationY = 0;
+        float mScaleX = 1, mScaleY = 1;
+        float mPivotX = 0, mPivotY = 0;
+        bool mHasOverlappingRendering = false;
+        bool mPivotExplicitlySet = false;
+        bool mMatrixOrPivotDirty = false;
+        bool mProjectBackwards = false;
+        bool mProjectionReceiver = false;
+        Rect mClipBounds;
         Outline mOutline;
         RevealClip mRevealClip;
-        int mClippingFlags;
-        bool mProjectBackwards;
-        bool mProjectionReceiver;
-        float mAlpha;
-        bool mHasOverlappingRendering;
-        float mElevation;
-        float mTranslationX, mTranslationY, mTranslationZ;
-        float mRotation, mRotationX, mRotationY;
-        float mScaleX, mScaleY;
-        float mPivotX, mPivotY;
-        int mLeft, mTop, mRight, mBottom;
-        int mWidth, mHeight;
-        bool mPivotExplicitlySet;
-        bool mMatrixOrPivotDirty;
-        Rect mClipBounds;
     } mPrimitiveFields;
 
     SkMatrix* mStaticMatrix;
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index 0084a8e..63821dd 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -51,7 +51,10 @@
         outBounds->set(mX - mRadius, mY - mRadius,
                 mX + mRadius, mY + mRadius);
     }
+
     float getRadius() const { return mRadius; }
+    float getX() const { return mX; }
+    float getY() const { return mY; }
 
     const SkPath* getPath() const {
         if (!mShouldClip) return nullptr;
diff --git a/libs/hwui/protos/ProtoHelpers.h b/libs/hwui/protos/ProtoHelpers.h
new file mode 100644
index 0000000..832e312
--- /dev/null
+++ b/libs/hwui/protos/ProtoHelpers.h
@@ -0,0 +1,41 @@
+/*
+ * 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 PROTOHELPERS_H
+#define PROTOHELPERS_H
+
+#include "Rect.h"
+#include "protos/hwui.pb.h"
+
+namespace android {
+namespace uirenderer {
+
+void set(proto::RectF* dest, const Rect& src) {
+    dest->set_left(src.left);
+    dest->set_top(src.top);
+    dest->set_right(src.right);
+    dest->set_bottom(src.bottom);
+}
+
+void set(std::string* dest, const SkPath& src) {
+    size_t size = src.writeToMemory(nullptr);
+    dest->resize(size);
+    src.writeToMemory(&*dest->begin());
+}
+
+} // namespace uirenderer
+} // namespace android
+
+#endif // PROTOHELPERS_H
diff --git a/libs/hwui/protos/hwui.proto b/libs/hwui/protos/hwui.proto
new file mode 100644
index 0000000..dcff80a
--- /dev/null
+++ b/libs/hwui/protos/hwui.proto
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package android.uirenderer.proto;
+
+option optimize_for = LITE_RUNTIME;
+
+message RenderNode {
+    required uint64 id = 1;
+    required string name = 2;
+    required RenderProperties properties = 3;
+    optional DisplayList display_list = 4;
+    repeated RenderNode children = 5;
+};
+
+message RenderProperties {
+    required int32 left = 1;
+    required int32 right = 2;
+    required int32 top = 3;
+    required int32 bottom = 4;
+    required int32 clip_flags = 5;
+    required float alpha = 6;
+    required float translation_x = 7;
+    required float translation_y = 8;
+    required float translation_z = 9;
+    required float elevation = 10;
+    required float rotation = 11;
+    required float rotation_x = 12;
+    required float rotation_y = 13;
+    required float scale_x = 14;
+    required float scale_y = 15;
+    required float pivot_x = 16;
+    required float pivot_y = 17;
+    required bool has_overlapping_rendering = 18;
+    required bool pivot_explicitly_set = 19;
+    required bool project_backwards = 20;
+    required bool projection_receiver = 21;
+    required RectF clip_bounds = 22;
+    optional Outline outline = 23;
+    optional RevealClip reveal_clip = 24;
+};
+
+message RectF {
+    required float left = 1;
+    required float right = 2;
+    required float top = 3;
+    required float bottom = 4;
+}
+
+message Outline {
+    required bool should_clip = 1;
+    enum Type {
+        None = 0;
+        Empty = 1;
+        ConvexPath = 2;
+        RoundRect = 3;
+    }
+    required Type type = 2;
+    required RectF bounds = 3;
+    required float radius = 4;
+    required float alpha = 5;
+    optional bytes path = 6;
+}
+
+message RevealClip {
+    required float x = 1;
+    required float y = 2;
+    required float radius = 3;
+}
+
+message DisplayList {
+    optional int32 projection_receive_index = 1;
+    repeated DrawOp draw_ops = 2;
+}
+
+message DrawOp {
+    oneof drawop {
+        DrawOp_RenderNode render_node = 1;
+    }
+}
+
+message DrawOp_RenderNode {
+    optional RenderNode node = 1;
+}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 7cb7738..1673802 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -26,15 +26,22 @@
 #include "RenderThread.h"
 #include "renderstate/RenderState.h"
 #include "renderstate/Stencil.h"
+#include "protos/hwui.pb.h"
+
+#include <cutils/properties.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
+#include <private/hwui/DrawGlInfo.h>
+#include <strings.h>
 
 #include <algorithm>
-#include <strings.h>
-#include <cutils/properties.h>
-#include <private/hwui/DrawGlInfo.h>
+#include <fcntl.h>
+#include <sys/stat.h>
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
 
+#define ENABLE_RENDERNODE_SERIALIZATION false
+
 #define LOG_FRAMETIME_MMA 0
 
 #if LOG_FRAMETIME_MMA
@@ -480,6 +487,40 @@
     mRenderThread.jankTracker().reset();
 }
 
+void CanvasContext::serializeDisplayListTree() {
+#if ENABLE_RENDERNODE_SERIALIZATION
+    using namespace google::protobuf::io;
+    char package[128];
+    // Check whether tracing is enabled for this process.
+    FILE * file = fopen("/proc/self/cmdline", "r");
+    if (file) {
+        if (!fgets(package, 128, file)) {
+            ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
+            fclose(file);
+            return;
+        }
+        fclose(file);
+    } else {
+        ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
+                errno);
+        return;
+    }
+    char path[1024];
+    snprintf(path, 1024, "/data/data/%s/cache/rendertree_dump", package);
+    int fd = open(path, O_CREAT | O_WRONLY, S_IRWXU | S_IRGRP | S_IROTH);
+    if (fd == -1) {
+        ALOGD("Failed to open '%s'", path);
+        return;
+    }
+    proto::RenderNode tree;
+    // TODO: Streaming writes?
+    mRootRenderNode->copyTo(&tree);
+    std::string data = tree.SerializeAsString();
+    write(fd, data.c_str(), data.length());
+    close(fd);
+#endif
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 0ceb9f1..6a79320 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -111,6 +111,8 @@
     void setName(const std::string&& name) { mName = name; }
     const std::string& name() { return mName; }
 
+    void serializeDisplayListTree();
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a3a0163..b838811 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -490,6 +490,17 @@
     post(task);
 }
 
+CREATE_BRIDGE1(serializeDisplayListTree, CanvasContext* context) {
+    args->context->serializeDisplayListTree();
+    return nullptr;
+}
+
+void RenderProxy::serializeDisplayListTree() {
+    SETUP_TASK(serializeDisplayListTree);
+    args->context = mContext;
+    post(task);
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 0d2c7be..e7356db 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -104,6 +104,8 @@
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
     ANDROID_API void setProcessStatsBuffer(int fd);
 
+    ANDROID_API void serializeDisplayListTree();
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index 483fb35..0bbf08c 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -26,6 +26,8 @@
 
 #include "TestContext.h"
 
+#include "protos/hwui.pb.h"
+
 #include <stdio.h>
 #include <unistd.h>
 
diff --git a/libs/hwui/unit_tests/CanvasStateTests.cpp b/libs/hwui/unit_tests/CanvasStateTests.cpp
new file mode 100644
index 0000000..79852be
--- /dev/null
+++ b/libs/hwui/unit_tests/CanvasStateTests.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "CanvasState.h"
+
+#include "Matrix.h"
+#include "Rect.h"
+#include "utils/LinearAllocator.h"
+
+#include <gtest/gtest.h>
+#include <SkPath.h>
+#include <SkRegion.h>
+#include <SkCanvas.h>
+
+namespace android {
+namespace uirenderer {
+
+class NullClient: public CanvasStateClient {
+    void onViewportInitialized() override {}
+    void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
+    GLuint getTargetFbo() const override { return 0; }
+};
+
+static NullClient sNullClient;
+
+static bool approxEqual(const Matrix4& a, const Matrix4& b) {
+    for (int i = 0; i < 16; i++) {
+        if (!MathUtils::areEqual(a[i], b[i])) {
+            return false;
+        }
+    }
+    return true;
+}
+
+TEST(CanvasState, gettersAndSetters) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    ASSERT_EQ(state.getWidth(), 200);
+    ASSERT_EQ(state.getHeight(), 200);
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 20, 0);
+    state.setMatrix(simpleTranslate);
+
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200));
+    ASSERT_EQ(state.getLocalClipBounds(), Rect(-10, -20, 190, 180));
+    EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    EXPECT_TRUE(state.clipIsSimple());
+}
+
+TEST(CanvasState, simpleClipping) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 100, 100));
+
+    state.clipRect(10, 10, 200, 200, SkRegion::kIntersect_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10, 100, 100));
+
+    state.clipRect(50, 50, 150, 150, SkRegion::kReplace_Op);
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(50, 50, 150, 150));
+}
+
+TEST(CanvasState, complexClipping) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // rotated clip causes complex clip
+        state.rotate(10);
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // subtracted clip causes complex clip
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipRect(50, 50, 150, 150, SkRegion::kDifference_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+
+    state.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
+    {
+        // complex path causes complex clip
+        SkPath path;
+        path.addOval(SkRect::MakeWH(200, 200));
+        EXPECT_TRUE(state.clipIsSimple());
+        state.clipPath(&path, SkRegion::kDifference_Op);
+        EXPECT_FALSE(state.clipIsSimple());
+    }
+    state.restore();
+}
+
+TEST(CanvasState, saveAndRestore) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kClip_SaveFlag);
+    {
+        state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+    }
+    state.restore();
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 200, 200)); // verify restore
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 10, 0);
+    state.save(SkCanvas::kMatrix_SaveFlag);
+    {
+        state.translate(10, 10, 0);
+        EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    }
+    state.restore();
+    EXPECT_FALSE(approxEqual(*state.currentTransform(), simpleTranslate));
+}
+
+TEST(CanvasState, saveAndRestoreButNotTooMuch) {
+    CanvasState state(sNullClient);
+    state.setViewport(200, 200);
+    state.initializeSaveStack(0, 0, state.getWidth(), state.getHeight(), Vector3());
+
+    state.save(SkCanvas::kMatrix_SaveFlag); // Note: clip not saved
+    {
+        state.clipRect(0, 0, 10, 10, SkRegion::kIntersect_Op);
+        ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10));
+    }
+    state.restore();
+    ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(0, 0, 10, 10)); // verify not restored
+
+    Matrix4 simpleTranslate;
+    simpleTranslate.loadTranslate(10, 10, 0);
+    state.save(SkCanvas::kClip_SaveFlag); // NOTE: matrix not saved
+    {
+        state.translate(10, 10, 0);
+        EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
+    }
+    state.restore();
+    EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
+}
+
+}
+}
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index 01cf5d2..0abe88b 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -140,7 +140,7 @@
 }
 
 void* LinearAllocator::start(Page* p) {
-    return ALIGN_PTR(((size_t*)p) + sizeof(Page));
+    return ALIGN_PTR((size_t)p + sizeof(Page));
 }
 
 void* LinearAllocator::end(Page* p) {
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index fbe047d..3cd157e 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -257,11 +257,12 @@
      * on completion, and must be done by the caller.
      *
      * @param objectHandle handle of the target file
+     * @param size size of the file in bytes
      * @param descriptor file descriptor to read the data from.
      * @return true if the file transfer succeeds
      */
-    public boolean sendObject(int objectHandle, ParcelFileDescriptor descriptor) {
-        return native_send_object(objectHandle, descriptor.getFd());
+    public boolean sendObject(int objectHandle, int size, ParcelFileDescriptor descriptor) {
+        return native_send_object(objectHandle, size, descriptor.getFd());
     }
 
     /**
@@ -294,6 +295,6 @@
     private native long native_get_storage_id(int objectHandle);
     private native boolean native_import_file(int objectHandle, String destPath);
     private native boolean native_import_file(int objectHandle, int fd);
-    private native boolean native_send_object(int objectHandle, int fd);
+    private native boolean native_send_object(int objectHandle, int size, int fd);
     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
 }
diff --git a/media/java/android/mtp/MtpObjectInfo.java b/media/java/android/mtp/MtpObjectInfo.java
index f79d52e..64aa997 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -273,25 +273,30 @@
         public Builder(MtpObjectInfo objectInfo) {
             mObjectInfo = new MtpObjectInfo();
             mObjectInfo.mHandle = -1;
-            mObjectInfo.mAssociationDesc = mObjectInfo.mAssociationDesc;
-            mObjectInfo.mAssociationType = mObjectInfo.mAssociationType;
-            mObjectInfo.mCompressedSize = mObjectInfo.mCompressedSize;
-            mObjectInfo.mDateCreated = mObjectInfo.mDateCreated;
-            mObjectInfo.mDateModified = mObjectInfo.mDateModified;
-            mObjectInfo.mFormat = mObjectInfo.mFormat;
-            mObjectInfo.mImagePixDepth = mObjectInfo.mImagePixDepth;
-            mObjectInfo.mImagePixHeight = mObjectInfo.mImagePixHeight;
-            mObjectInfo.mImagePixWidth = mObjectInfo.mImagePixWidth;
-            mObjectInfo.mKeywords = mObjectInfo.mKeywords;
-            mObjectInfo.mName = mObjectInfo.mName;
-            mObjectInfo.mParent = mObjectInfo.mParent;
-            mObjectInfo.mProtectionStatus = mObjectInfo.mProtectionStatus;
-            mObjectInfo.mSequenceNumber = mObjectInfo.mSequenceNumber;
-            mObjectInfo.mStorageId = mObjectInfo.mStorageId;
-            mObjectInfo.mThumbCompressedSize = mObjectInfo.mThumbCompressedSize;
-            mObjectInfo.mThumbFormat = mObjectInfo.mThumbFormat;
-            mObjectInfo.mThumbPixHeight = mObjectInfo.mThumbPixHeight;
-            mObjectInfo.mThumbPixWidth = mObjectInfo.mThumbPixWidth;
+            mObjectInfo.mAssociationDesc = objectInfo.mAssociationDesc;
+            mObjectInfo.mAssociationType = objectInfo.mAssociationType;
+            mObjectInfo.mCompressedSize = objectInfo.mCompressedSize;
+            mObjectInfo.mDateCreated = objectInfo.mDateCreated;
+            mObjectInfo.mDateModified = objectInfo.mDateModified;
+            mObjectInfo.mFormat = objectInfo.mFormat;
+            mObjectInfo.mImagePixDepth = objectInfo.mImagePixDepth;
+            mObjectInfo.mImagePixHeight = objectInfo.mImagePixHeight;
+            mObjectInfo.mImagePixWidth = objectInfo.mImagePixWidth;
+            mObjectInfo.mKeywords = objectInfo.mKeywords;
+            mObjectInfo.mName = objectInfo.mName;
+            mObjectInfo.mParent = objectInfo.mParent;
+            mObjectInfo.mProtectionStatus = objectInfo.mProtectionStatus;
+            mObjectInfo.mSequenceNumber = objectInfo.mSequenceNumber;
+            mObjectInfo.mStorageId = objectInfo.mStorageId;
+            mObjectInfo.mThumbCompressedSize = objectInfo.mThumbCompressedSize;
+            mObjectInfo.mThumbFormat = objectInfo.mThumbFormat;
+            mObjectInfo.mThumbPixHeight = objectInfo.mThumbPixHeight;
+            mObjectInfo.mThumbPixWidth = objectInfo.mThumbPixWidth;
+        }
+
+        public Builder setObjectHandle(int value) {
+            mObjectInfo.mHandle = value;
+            return this;
         }
 
         public Builder setAssociationDesc(int value) {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 9dd3861..2a46ee7 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -412,18 +412,13 @@
 }
 
 static jboolean
-android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint fd)
+android_mtp_MtpDevice_send_object(JNIEnv *env, jobject thiz, jint object_id, jint size, jint fd)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
     if (!device)
         return JNI_FALSE;
-    MtpObjectInfo* object_info = device->getObjectInfo(object_id);
-    if (!object_info)
-        return JNI_FALSE;
 
-    bool result = device->sendObject(object_info, fd);
-    delete object_info;
-    return result;
+    return device->sendObject(object_id, size, fd);
 }
 
 static jobject
@@ -516,7 +511,7 @@
     {"native_import_file",      "(ILjava/lang/String;)Z",
                                         (void *)android_mtp_MtpDevice_import_file},
     {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
-    {"native_send_object",      "(II)Z",(void *)android_mtp_MtpDevice_send_object},
+    {"native_send_object",      "(III)Z",(void *)android_mtp_MtpDevice_send_object},
     {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
                                         (void *)android_mtp_MtpDevice_send_object_info}
 };
diff --git a/packages/BackupRestoreConfirmation/res/values-it/strings.xml b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
index 2325d40..b84edbc 100644
--- a/packages/BackupRestoreConfirmation/res/values-it/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
@@ -29,7 +29,7 @@
     <string name="device_encryption_backup_text" msgid="5866590762672844664">"Inserisci la tua password di crittografia dispositivo di seguito. Verrà utilizzata anche per crittografare l\'archivio di backup."</string>
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Inserisci una password da utilizzare per la crittografia dei dati di backup completi. Se non ne inserisci una, verrà utilizzata la tua password di backup corrente:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"Se desideri crittografare tutti i dati di backup, inserisci una password qui di seguito:"</string>
-    <string name="backup_enc_password_required" msgid="7889652203371654149">"Il dispositivo è crittografato, pertanto devi crittografare il backup. Inserisci una password di seguito:"</string>
+    <string name="backup_enc_password_required" msgid="7889652203371654149">"Il dispositivo è criptato, quindi devi criptare il backup. Inserisci una password di seguito:"</string>
     <string name="restore_enc_password_text" msgid="6140898525580710823">"Se i dati di ripristino sono crittografati, inserisci la password qui di seguito:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Avvio del backup..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Backup terminato"</string>
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 3430bb4..1a4e3eb 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -5,9 +5,29 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \
-    android-support-v7-recyclerview \
-    guava
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+# The design lib requires that the client package use appcompat themes.
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-appcompat
+# Supplies material design components, e.g. Snackbar.
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
+LOCAL_STATIC_JAVA_LIBRARIES += guava
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+# Not quite sure why it is necessary to explicitly pull in resources from the
+# appcompat lib, but the demo code indicates it's necessary (see
+# development/samples/Support7Demos/Android.mk)
+LOCAL_RESOURCE_DIR += \
+  frameworks/support/v7/appcompat/res \
+  frameworks/support/design/res \
+  frameworks/support/v7/recyclerview/res
+
+# Again, required to pull in appcompat resources.  See abovementioned demo code.
+LOCAL_AAPT_FLAGS := \
+  --auto-add-overlay \
+  --extra-packages android.support.v7.appcompat \
+  --extra-packages android.support.design \
+  --extra-packages android.support.v7.recyclerview
 
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index 221de13..9769f26 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -25,7 +25,8 @@
         android:layout_height="?android:attr/actionBarSize"
         android:background="?android:attr/colorPrimary"
         android:elevation="8dp"
-        android:theme="?android:attr/actionBarTheme">
+        android:theme="?actionBarTheme"
+        android:popupTheme="?actionBarPopupTheme">
 
         <Spinner
             android:id="@+id/stack"
diff --git a/packages/DocumentsUI/res/values-sw720dp/styles.xml b/packages/DocumentsUI/res/values-sw720dp/styles.xml
index 0b03a94..f4bc88e 100644
--- a/packages/DocumentsUI/res/values-sw720dp/styles.xml
+++ b/packages/DocumentsUI/res/values-sw720dp/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="DialogWhenReallyLarge" parent="@*android:style/Theme.Material.DayNight.Dialog">
+    <style name="DocumentsBaseTheme" parent="@*android:style/Theme.Material.DayNight.Dialog">
         <!-- We do not specify width of window here because the max size of
              floating window specified by windowFixedWidthis is limited. -->
         <item name="*android:windowFixedHeightMajor">80%</item>
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index 0735ff9..6002dde 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -22,6 +22,10 @@
     <color name="material_blue_700">#ff1976d2</color>
     <color name="material_blue_500">#ff2196f3</color>
 
+    <color name="primary_dark">@*android:color/material_blue_grey_900</color>
+    <color name="primary">@*android:color/material_blue_grey_800</color>
+    <color name="accent">@*android:color/material_deep_teal_500</color>
+
     <color name="directory_background">@color/material_grey_300</color>
     <color name="item_doc_grid_background">#FFFFFFFF</color>
     <color name="item_doc_grid_protect_background">#88000000</color>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 616f4dd..4b44d7c 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -139,6 +139,13 @@
         <item quantity="one">Moving <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
         <item quantity="other">Moving <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
     </plurals>
+    <!-- Text shown when files are deleted -->
+    <plurals name="deleting">
+        <item quantity="one">Deleting <xliff:g id="count" example="1">%1$d</xliff:g> file.</item>
+        <item quantity="other">Deleting <xliff:g id="count" example="3">%1$d</xliff:g> files.</item>
+    </plurals>
+    <!-- Text shown for the undo button -->
+    <string name="undo">Undo</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for copying files [CHAR LIMIT=32] -->
     <string name="copy_preparing">Preparing for copy\u2026</string>
     <!-- Text shown on the notification while DocumentsUI performs setup in preparation for moving files [CHAR LIMIT=32] -->
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index fa94ff1..22add98 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -16,16 +16,18 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="DialogWhenReallyLarge" parent="@android:style/Theme.Material.DayNight.DarkActionBar" />
+    <style name="DocumentsBaseTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar" />
+    <style name="ActionBarTheme" parent="@*android:style/ThemeOverlay.Material.Dark.ActionBar" />
+    <style name="ActionBarPopupTheme" parent="@*android:style/ThemeOverlay.Material.Light" />
 
-    <style name="DocumentsTheme" parent="@style/DialogWhenReallyLarge">
-        <item name="android:actionBarWidgetTheme">@null</item>
-        <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
-        <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
+    <style name="DocumentsTheme" parent="@style/DocumentsBaseTheme">
+        <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@style/ActionBarTheme</item>
+        <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
 
-        <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_900</item>
-        <item name="android:colorPrimary">@*android:color/material_blue_grey_800</item>
-        <item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
+        <item name="android:colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:colorPrimary">@color/primary</item>
+        <item name="android:colorAccent">@color/accent</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -37,14 +39,10 @@
         <item name="android:alertDialogTheme">@android:style/Theme.Material.Light.Dialog.Alert</item>
     </style>
 
-    <style name="DocumentsNonDialogTheme" parent="@android:style/Theme.Material.DayNight.DarkActionBar">
-        <item name="android:actionBarWidgetTheme">@null</item>
-        <item name="android:actionBarTheme">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
-        <item name="android:actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
-
-        <item name="android:colorPrimaryDark">@*android:color/material_blue_grey_900</item>
-        <item name="android:colorPrimary">@*android:color/material_blue_grey_800</item>
-        <item name="android:colorAccent">@*android:color/material_deep_teal_500</item>
+    <style name="DocumentsBaseTheme.FullScreen" parent="@style/Theme.AppCompat.Light.DarkActionBar">
+        <item name="actionBarWidgetTheme">@null</item>
+        <item name="actionBarTheme">@style/ActionBarTheme</item>
+        <item name="actionBarPopupTheme">@style/ActionBarPopupTheme</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -55,6 +53,12 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
 
+    <style name="DocumentsNonDialogTheme" parent="@style/DocumentsBaseTheme.FullScreen">
+        <item name="android:colorPrimaryDark">@color/primary_dark</item>
+        <item name="android:colorPrimary">@color/primary</item>
+        <item name="android:colorAccent">@color/accent</item>
+    </style>
+
     <style name="ActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
         <item name="android:background">@color/material_grey_600</item>
     </style>
@@ -63,21 +67,12 @@
         <item name="android:colorAccent">@color/material_blue_700</item>
     </style>
 
-    <style name="FilesTheme" parent="@android:style/Theme.Material.DayNight.DarkActionBar">
-        <item name="android:actionBarWidgetTheme">@null</item>
-
-        <item name="android:colorPrimaryDark">@color/status_bar_background</item>
+    <style name="FilesTheme" parent="@style/DocumentsBaseTheme.FullScreen">
+        <item name="android:colorPrimaryDark">@color/material_blue_700</item>
         <item name="android:colorPrimary">@color/material_blue_500</item>
         <item name="android:colorAccent">@color/material_blue_700</item>
         <item name="android:actionModeStyle">@style/ActionModeStyle</item>
 
-        <item name="android:listDivider">@*android:drawable/list_divider_material</item>
-
-        <item name="android:windowActionBar">false</item>
-        <item name="android:windowActionModeOverlay">true</item>
-        <item name="android:windowNoTitle">true</item>
-
-        <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
         <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
     </style>
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 8b92331..f8ec8f1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -56,6 +56,7 @@
 
 public class CopyService extends IntentService {
     public static final String TAG = "CopyService";
+    public static final boolean DEBUG = false;
 
     private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
     public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
@@ -159,6 +160,7 @@
             // Catch-all to prevent any copy errors from wedging the app.
             Log.e(TAG, "Exceptions occurred during copying", e);
         } finally {
+            if (DEBUG) Log.d(TAG, "Cleaning up after copy");
             ContentProviderClient.releaseQuietly(mSrcClient);
             ContentProviderClient.releaseQuietly(mDstClient);
 
@@ -166,10 +168,12 @@
             mNotificationManager.cancel(mJobId, 0);
 
             if (mFailedFiles.size() > 0) {
+                Log.e(TAG, mFailedFiles.size() + " files failed to copy");
                 final Context context = getApplicationContext();
                 final Intent navigateIntent = new Intent(context, FilesActivity.class);
                 navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
                 navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
+                navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode);
                 navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
 
                 final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ?
@@ -186,6 +190,7 @@
                         .setAutoCancel(true);
                 mNotificationManager.notify(mJobId, 0, errorBuilder.build());
             }
+            if (DEBUG) Log.d(TAG, "Done cleaning up");
         }
     }
 
@@ -398,6 +403,9 @@
      */
     private void copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode)
             throws RemoteException {
+        if (DEBUG) Log.d(TAG, "Copying " + srcInfo.displayName + " (" + srcInfo.derivedUri + ")" +
+            " to " + dstDirInfo.displayName + " (" + dstDirInfo.derivedUri + ")");
+
         final Uri dstUri = DocumentsContract.createDocument(mDstClient, dstDirInfo.derivedUri,
                 srcInfo.mimeType, srcInfo.displayName);
         if (dstUri == null) {
@@ -499,10 +507,28 @@
             srcFile.checkError();
         } catch (IOException e) {
             copyError = e;
+
             try {
-                dstFile.closeWithError(copyError.getMessage());
-            } catch (IOException closeError) {
-                Log.e(TAG, "Error closing destination", closeError);
+                DocumentInfo info = DocumentInfo.fromUri(getContentResolver(), srcUri);
+                mFailedFiles.add(info);
+                Log.e(TAG, "Error while copying " + info.displayName + " (" + info.derivedUri + ")",
+                        copyError);
+            } catch (FileNotFoundException ignore) {
+                // Generate a dummy DocumentInfo so an error still gets reflected in the UI for this
+                // file.
+                DocumentInfo info = new DocumentInfo();
+                info.derivedUri = srcUri;
+                info.displayName = "Unknown [" + srcUri + "]";
+                mFailedFiles.add(info);
+                Log.e(TAG, "Error while copying " + srcUri, copyError);
+            }
+
+            if (dstFile != null) {
+                try {
+                    dstFile.closeWithError(copyError.getMessage());
+                } catch (IOException closeError) {
+                    Log.e(TAG, "Error closing destination", closeError);
+                }
             }
         } finally {
             // This also ensures the file descriptors are closed.
@@ -510,16 +536,6 @@
             IoUtils.closeQuietly(dst);
         }
 
-        if (copyError != null) {
-            // Log errors.
-            Log.e(TAG, "Error while copying " + srcUri.toString(), copyError);
-            try {
-                mFailedFiles.add(DocumentInfo.fromUri(getContentResolver(), srcUri));
-            } catch (FileNotFoundException ignore) {
-                Log.w(TAG, "Source file gone: " + srcUri, copyError);
-                // The source file is gone.
-            }
-        }
 
         if (copyError != null || mIsCancelled) {
             // Clean up half-copied files.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index c28806b..edf829d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -61,6 +61,8 @@
 import android.os.SystemProperties;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
@@ -73,6 +75,7 @@
 import android.text.format.Time;
 import android.util.Log;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.view.ActionMode;
 import android.view.DragEvent;
 import android.view.GestureDetector;
@@ -83,6 +86,7 @@
 import android.view.View;
 import android.view.View.OnLayoutChangeListener;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.widget.ImageView;
 import android.widget.TextView;
 import android.widget.Toast;
@@ -96,7 +100,6 @@
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.util.Preconditions;
-
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
@@ -129,6 +132,8 @@
     private static final String EXTRA_QUERY = "query";
     private static final String EXTRA_IGNORE_STATE = "ignoreState";
 
+    private final Model mModel = new Model();
+
     private final Handler mHandler = new Handler(Looper.getMainLooper());
 
     private View mEmptyView;
@@ -147,7 +152,6 @@
     private LoaderCallbacks<DirectoryResult> mCallbacks;
     private FragmentTuner mFragmentTuner;
     private DocumentClipper mClipper;
-    private MultiSelectManager mSelectionManager;
     // These are lazily initialized.
     private LinearLayoutManager mListLayout;
     private GridLayoutManager mGridLayout;
@@ -261,7 +265,7 @@
         }
 
         // Clear any outstanding selection
-        mSelectionManager.clearSelection();
+        mModel.clearSelection();
     }
 
     @Override
@@ -290,14 +294,17 @@
                     }
                 };
 
-        mSelectionManager = new MultiSelectManager(
+        // TODO: instead of inserting the view into the constructor, extract listener-creation code
+        // and set the listener on the view after the fact.  Then the view doesn't need to be passed
+        // into the selection manager which is passed into the model.
+        MultiSelectManager selMgr= new MultiSelectManager(
                 mRecView,
                 listener,
                 state.allowMultiple
                     ? MultiSelectManager.MODE_MULTIPLE
                     : MultiSelectManager.MODE_SINGLE);
-
-        mSelectionManager.addCallback(new SelectionModeListener());
+        selMgr.addCallback(new SelectionModeListener());
+        mModel.setSelectionManager(selMgr);
 
         mType = getArguments().getInt(EXTRA_TYPE);
         mStateKey = buildStateKey(root, doc);
@@ -367,7 +374,9 @@
 
                 if (!isAdded()) return;
 
-                mAdapter.replaceResult(result);
+                // TODO: make the adapter listen to the model
+                mModel.update(result);
+                mAdapter.update();
 
                 // Push latest state up to UI
                 // TODO: if mode change was racing with us, don't overwrite it
@@ -380,7 +389,7 @@
                 updateDisplayState();
 
                 // When launched into empty recents, show drawer
-                if (mType == TYPE_RECENT_OPEN && mAdapter.isEmpty() && !state.stackTouched &&
+                if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.stackTouched &&
                         context instanceof DocumentsActivity) {
                     ((DocumentsActivity) context).setRootsDrawerOpen(true);
                 }
@@ -398,7 +407,9 @@
 
             @Override
             public void onLoaderReset(Loader<DirectoryResult> loader) {
-                mAdapter.replaceResult(null);
+                // TODO: make the adapter listen to the model.
+                mModel.update(null);
+                mAdapter.update();
             }
         };
 
@@ -433,7 +444,7 @@
     }
 
     private boolean onSingleTapUp(MotionEvent e) {
-        if (Events.isTouchEvent(e) && mSelectionManager.getSelection().isEmpty()) {
+        if (Events.isTouchEvent(e) && mModel.getSelection().isEmpty()) {
             int position = getEventAdapterPosition(e);
             if (position != RecyclerView.NO_POSITION) {
                 return handleViewItem(position);
@@ -454,14 +465,14 @@
     }
 
     private boolean handleViewItem(int position) {
-        final Cursor cursor = mAdapter.getItem(position);
+        final Cursor cursor = mModel.getItem(position);
         checkNotNull(cursor, "Cursor cannot be null.");
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         if (isDocumentEnabled(docMimeType, docFlags)) {
             final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-            ((BaseActivity) getActivity()).onDocumentPicked(doc, mAdapter);
-            mSelectionManager.clearSelection();
+            ((BaseActivity) getActivity()).onDocumentPicked(doc, mModel);
+            mModel.clearSelection();
             return true;
         }
         return false;
@@ -565,6 +576,9 @@
         }
 
         mRecView.setLayoutManager(layout);
+        // TODO: Once b/23691541 is resolved, use a listener within MultiSelectManager instead of
+        // imperatively calling this function.
+        mModel.mSelectionManager.handleLayoutChanged();
         // setting layout manager automatically invalidates existing ViewHolders.
         mThumbSize = new Point(thumbSize, thumbSize);
     }
@@ -598,7 +612,7 @@
         public boolean onBeforeItemStateChange(int position, boolean selected) {
             // Directories and footer items cannot be checked
             if (selected) {
-                final Cursor cursor = mAdapter.getItem(position);
+                final Cursor cursor = mModel.getItem(position);
                 checkNotNull(cursor, "Cursor cannot be null.");
                 final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                 final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -610,7 +624,7 @@
         @Override
         public void onItemStateChanged(int position, boolean selected) {
 
-            final Cursor cursor = mAdapter.getItem(position);
+            final Cursor cursor = mModel.getItem(position);
             checkNotNull(cursor, "Cursor cannot be null.");
 
             final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
@@ -621,7 +635,7 @@
 
         @Override
         public void onSelectionChanged() {
-            mSelectionManager.getSelection(mSelected);
+            mModel.getSelection(mSelected);
             if (mSelected.size() > 0) {
                 if (DEBUG) Log.d(TAG, "Maybe starting action mode.");
                 if (mActionMode == null) {
@@ -651,7 +665,7 @@
             if (DEBUG) Log.d(TAG, "Handling action mode destroyed.");
             mActionMode = null;
             // clear selection
-            mSelectionManager.clearSelection();
+            mModel.clearSelection();
             mSelected.clear();
             mNoDeleteCount = 0;
         }
@@ -659,8 +673,8 @@
         @Override
         public boolean onCreateActionMode(ActionMode mode, Menu menu) {
             mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
-            mode.setTitle(TextUtils.formatSelectedCount(mSelectionManager.getSelection().size()));
-            return mSelectionManager.getSelection().size() > 0;
+            mode.setTitle(TextUtils.formatSelectedCount(mModel.getSelection().size()));
+            return mModel.getSelection().size() > 0;
         }
 
         @Override
@@ -679,8 +693,7 @@
         @Override
         public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
 
-            Selection selection = new Selection();
-            mSelectionManager.getSelection(selection);
+            Selection selection = mModel.getSelection(new Selection());
 
             final int id = item.getItemId();
             if (id == R.id.menu_open) {
@@ -793,41 +806,33 @@
     }
 
     private void deleteDocuments(final Selection selected) {
-        final Context context = getActivity();
-        final ContentResolver resolver = context.getContentResolver();
+        Context context = getActivity();
+        ContentResolver resolver = context.getContentResolver();
+        String message = Shared.getQuantityString(context, R.plurals.deleting, selected.size());
 
-        new GetDocumentsTask() {
-            @Override
-            void onDocumentsReady(List<DocumentInfo> docs) {
-                boolean hadTrouble = false;
-                for (DocumentInfo doc : docs) {
-                    if (!doc.isDeleteSupported()) {
-                        Log.w(TAG, "Skipping " + doc);
-                        hadTrouble = true;
-                        continue;
-                    }
+        mModel.markForDeletion(selected);
 
-                    ContentProviderClient client = null;
-                    try {
-                        client = DocumentsApplication.acquireUnstableProviderOrThrow(
-                                resolver, doc.derivedUri.getAuthority());
-                        DocumentsContract.deleteDocument(client, doc.derivedUri);
-                    } catch (Exception e) {
-                        Log.w(TAG, "Failed to delete " + doc);
-                        hadTrouble = true;
-                    } finally {
-                        ContentProviderClient.releaseQuietly(client);
-                    }
-                }
-
-                if (hadTrouble) {
-                    Toast.makeText(
-                            context,
-                            R.string.toast_failed_delete,
-                            Toast.LENGTH_SHORT).show();
-                }
-            }
-        }.execute(selected);
+        Activity activity = getActivity();
+        Snackbar.make(this.getView(), message, Snackbar.LENGTH_LONG)
+                .setAction(
+                        R.string.undo,
+                        new android.view.View.OnClickListener() {
+                            @Override
+                            public void onClick(View view) {}
+                        })
+                .setCallback(
+                        new Snackbar.Callback() {
+                            @Override
+                            public void onDismissed(Snackbar snackbar, int event) {
+                                if (event == Snackbar.Callback.DISMISS_EVENT_ACTION) {
+                                    mModel.undoDeletion();
+                                } else {
+                                    mModel.finalizeDeletion();
+                                }
+                                ;
+                            }
+                        })
+                .show();
     }
 
     private void transferDocuments(final Selection selected, final int mode) {
@@ -948,50 +953,31 @@
         }
     }
 
-    private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder>
-            implements DocumentContext {
+    private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
 
         private final Context mContext;
         private final LayoutInflater mInflater;
         // TODO: Bring back support for footers.
         private final List<Footer> mFooters = new ArrayList<>();
 
-        private Cursor mCursor;
-        private int mCursorCount;
-
         public DocumentsAdapter(Context context) {
             mContext = context;
             mInflater = LayoutInflater.from(context);
         }
 
-        public void replaceResult(DirectoryResult result) {
-            if (DEBUG) Log.i(TAG, "Updating adapter with new result set.");
-            mCursor = result != null ? result.cursor : null;
-            mCursorCount = mCursor != null ? mCursor.getCount() : 0;
-
+        public void update() {
             mFooters.clear();
-
-            final Bundle extras = mCursor != null ? mCursor.getExtras() : null;
-            if (extras != null) {
-                final String info = extras.getString(DocumentsContract.EXTRA_INFO);
-                if (info != null) {
-                    mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, info));
-                }
-                final String error = extras.getString(DocumentsContract.EXTRA_ERROR);
-                if (error != null) {
-                    mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, error));
-                }
-                if (extras.getBoolean(DocumentsContract.EXTRA_LOADING, false)) {
-                    mFooters.add(new LoadingFooter());
-                }
+            if (mModel.info != null) {
+                mFooters.add(new MessageFooter(2, R.drawable.ic_dialog_info, mModel.info));
+            }
+            if (mModel.error != null) {
+                mFooters.add(new MessageFooter(3, R.drawable.ic_dialog_alert, mModel.error));
+            }
+            if (mModel.isLoading()) {
+                mFooters.add(new LoadingFooter());
             }
 
-            if (result != null && result.exception != null) {
-                mFooters.add(new MessageFooter(
-                        3, R.drawable.ic_dialog_alert, getString(R.string.query_error)));
-            }
-
-            if (isEmpty()) {
+            if (mModel.isEmpty()) {
                 mEmptyView.setVisibility(View.VISIBLE);
             } else {
                 mEmptyView.setVisibility(View.GONE);
@@ -1025,7 +1011,7 @@
             final ThumbnailCache thumbs = DocumentsApplication.getThumbnailsCache(
                     context, mThumbSize);
 
-            final Cursor cursor = getItem(position);
+            final Cursor cursor = mModel.getItem(position);
             checkNotNull(cursor, "Cursor cannot be null.");
 
             final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
@@ -1041,7 +1027,7 @@
 
             holder.docId = docId;
             final View itemView = holder.view;
-            itemView.setActivated(mSelectionManager.getSelection().contains(position));
+            itemView.setActivated(mModel.isSelected(position));
 
             final View line1 = itemView.findViewById(R.id.line1);
             final View line2 = itemView.findViewById(R.id.line2);
@@ -1214,44 +1200,21 @@
         }
 
         @Override
-        public Cursor getCursor() {
-            if (Looper.myLooper() != Looper.getMainLooper()) {
-                throw new IllegalStateException("Can't call getCursor from non-main thread.");
-            }
-            return mCursor;
-        }
-
-        private Cursor getItem(int position) {
-            if (position < mCursorCount) {
-                mCursor.moveToPosition(position);
-                return mCursor;
-            }
-
-            Log.w(TAG, "Returning null cursor for position: " + position);
-            if (DEBUG) Log.d(TAG, "...Adapter size: " + mCursorCount);
-            if (DEBUG) Log.d(TAG, "...Footer size: " + mFooters.size());
-            return null;
-        }
-
-        @Override
         public int getItemCount() {
-            return mCursorCount;
+            return mModel.getItemCount();
             // return mCursorCount + mFooters.size();
         }
 
         @Override
         public int getItemViewType(int position) {
-            if (position < mCursorCount) {
+            final int itemCount = mModel.getItemCount();
+            if (position < itemCount) {
                 return 0;
             } else {
-                position -= mCursorCount;
+                position -= itemCount;
                 return mFooters.get(position).getItemViewType();
             }
         }
-
-        private boolean isEmpty() {
-            return getItemCount() > 0;
-        }
     }
 
     private static String formatTime(Context context, long when) {
@@ -1328,27 +1291,6 @@
         return MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
     }
 
-    private List<DocumentInfo> getSelectedDocuments() {
-        Selection sel = mSelectionManager.getSelection(new Selection());
-        return getItemsAsDocuments(sel);
-    }
-
-    private List<DocumentInfo> getItemsAsDocuments(Selection items) {
-        if (items == null || items.size() == 0) {
-            return new ArrayList<>(0);
-        }
-
-        final List<DocumentInfo> docs =  new ArrayList<>(items.size());
-        final int size = items.size();
-        for (int i = 0; i < size; i++) {
-            final Cursor cursor = mAdapter.getItem(items.get(i));
-            checkNotNull(cursor, "Cursor cannot be null.");
-            final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-            docs.add(doc);
-        }
-        return docs;
-    }
-
     private void copyFromClipboard() {
         new AsyncTask<Void, Void, List<DocumentInfo>>() {
 
@@ -1426,7 +1368,7 @@
     }
 
     void copySelectedToClipboard() {
-        Selection sel = mSelectionManager.getSelection(new Selection());
+        Selection sel = mModel.getSelection(new Selection());
         copySelectionToClipboard(sel);
     }
 
@@ -1458,7 +1400,7 @@
      * @return true if the list of files can be copied to destination.
      */
     boolean canCopy(List<DocumentInfo> files, DocumentInfo dest) {
-        BaseActivity activity = (BaseActivity)getActivity();
+        BaseActivity activity = (BaseActivity) getActivity();
 
         final RootInfo root = activity.getCurrentRoot();
 
@@ -1475,7 +1417,7 @@
     }
 
     void selectAllFiles() {
-        boolean changed = mSelectionManager.setItemsSelected(0, mAdapter.getItemCount(), true);
+        boolean changed = mModel.selectAll();
         if (changed) {
             updateDisplayState();
         }
@@ -1518,10 +1460,10 @@
                     return true;
 
                 case DragEvent.ACTION_DROP:
-                    int dstPosition = mRecView.getChildAdapterPosition(v);
+                    int dstPosition = mRecView.getChildAdapterPosition(getContainingItemView(v));
                     DocumentInfo dstDir = null;
                     if (dstPosition != android.widget.AdapterView.INVALID_POSITION) {
-                        Cursor dstCursor = mAdapter.getItem(dstPosition);
+                        Cursor dstCursor = mModel.getItem(dstPosition);
                         checkNotNull(dstCursor, "Cursor cannot be null.");
                         dstDir = DocumentInfo.fromDirectoryCursor(dstCursor);
                         // TODO: Do not drop into the directory where the documents came from.
@@ -1533,6 +1475,19 @@
         }
     };
 
+    private View getContainingItemView(View view) {
+        while (true) {
+            if (view.getLayoutParams() instanceof RecyclerView.LayoutParams) {
+                return view;
+            }
+            ViewParent parent = view.getParent();
+            if (parent == null || !(parent instanceof View)) {
+                return null;
+            }
+            view = (View) parent;
+        }
+    }
+
     private View.OnLongClickListener mLongClickListener = new View.OnLongClickListener() {
         @Override
         public boolean onLongClick(View v) {
@@ -1551,21 +1506,21 @@
     };
 
     private List<DocumentInfo> getDraggableDocuments(View currentItemView) {
-        int position = mRecView.getChildAdapterPosition(currentItemView);
+        int position = mRecView.getChildAdapterPosition(getContainingItemView(currentItemView));
         if (position == android.widget.AdapterView.INVALID_POSITION) {
             return Collections.EMPTY_LIST;
         }
 
-        final List<DocumentInfo> selectedDocs = getSelectedDocuments();
+        final List<DocumentInfo> selectedDocs = mModel.getSelectedDocuments();
         if (!selectedDocs.isEmpty()) {
-            if (!mSelectionManager.getSelection().contains(position)) {
+            if (!mModel.isSelected(position)) {
                 // There is a selection that does not include the current item, drag nothing.
                 return Collections.EMPTY_LIST;
             }
             return selectedDocs;
         }
 
-        final Cursor cursor = mAdapter.getItem(position);
+        final Cursor cursor = mModel.getItem(position);
         checkNotNull(cursor, "Cursor cannot be null.");
         final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
 
@@ -1671,12 +1626,14 @@
             mShadow.setBounds(0, 0, mShadowDimension, mShadowDimension);
         }
 
+        @Override
         public void onProvideShadowMetrics(
                 Point shadowSize, Point shadowTouchPoint) {
             shadowSize.set(mShadowDimension, mShadowDimension);
             shadowTouchPoint.set(mShadowDimension / 2, mShadowDimension / 2);
         }
 
+        @Override
         public void onDrawShadow(Canvas canvas) {
             mShadow.draw(canvas);
         }
@@ -1706,7 +1663,7 @@
             extends AsyncTask<Selection, Void, List<DocumentInfo>> {
         @Override
         protected final List<DocumentInfo> doInBackground(Selection... selected) {
-            return getItemsAsDocuments(selected[0]);
+            return mModel.getDocuments(selected[0]);
         }
 
         @Override
@@ -1775,4 +1732,269 @@
         @Override
         public void afterActivityCreated(DirectoryFragment fragment) {}
     }
+
+    /**
+     * The data model for the current loaded directory.
+     */
+    private final class Model implements DocumentContext {
+        private MultiSelectManager mSelectionManager;
+        private int mCursorCount;
+        private boolean mIsLoading;
+        @Nullable private Cursor mCursor;
+        @Nullable private String info;
+        @Nullable private String error;
+        private SparseBooleanArray mMarkedForDeletion = new SparseBooleanArray();
+
+        /**
+         * Sets the selection manager used by the model.
+         * TODO: the model should instantiate the selection manager.  See onActivityCreated.
+         */
+        void setSelectionManager(MultiSelectManager mgr) {
+            mSelectionManager = mgr;
+        }
+
+        /**
+         * Selects all files in the current directory.
+         * @return true if the selection state changed for any files.
+         */
+        boolean selectAll() {
+            return mSelectionManager.setItemsSelected(0, mCursorCount, true);
+        }
+
+        /**
+         * Clones the current selection into the given Selection object.
+         * @param selection
+         * @return The selection that was passed in, for convenience.
+         */
+        Selection getSelection(Selection selection) {
+            return mSelectionManager.getSelection(selection);
+        }
+
+        /**
+         * @return The current selection (the live instance, not a copy).
+         */
+        Selection getSelection() {
+            return mSelectionManager.getSelection();
+        }
+
+        boolean isSelected(int position) {
+            return mSelectionManager.getSelection().contains(position);
+        }
+
+        void clearSelection() {
+            mSelectionManager.clearSelection();
+        }
+
+        void update(DirectoryResult result) {
+            if (DEBUG) Log.i(TAG, "Updating model with new result set.");
+
+            if (result == null) {
+                mCursor = null;
+                mCursorCount = 0;
+                info = null;
+                error = null;
+                mIsLoading = false;
+                return;
+            }
+
+            if (result.exception != null) {
+                Log.e(TAG, "Error while loading directory contents", result.exception);
+                error = getString(R.string.query_error);
+                return;
+            }
+
+            mCursor = result.cursor;
+            mCursorCount = mCursor.getCount();
+
+            final Bundle extras = mCursor.getExtras();
+            if (extras != null) {
+                info = extras.getString(DocumentsContract.EXTRA_INFO);
+                error = extras.getString(DocumentsContract.EXTRA_ERROR);
+                mIsLoading = extras.getBoolean(DocumentsContract.EXTRA_LOADING, false);
+            }
+        }
+
+        private int getItemCount() {
+            return mCursorCount - mMarkedForDeletion.size();
+        }
+
+        private Cursor getItem(int position) {
+            // Items marked for deletion are masked out of the UI.  To do this, for every marked
+            // item whose position is less than the requested item position, advance the requested
+            // position by 1.
+            final int originalPos = position;
+            final int size = mMarkedForDeletion.size();
+            for (int i = 0; i <= size; ++i) {
+                // It'd be more concise, but less efficient, to iterate over positions while calling
+                // mMarkedForDeletion.get.  Instead, iterate over deleted entries.
+                if (mMarkedForDeletion.keyAt(i) <= position && mMarkedForDeletion.valueAt(i)) {
+                    ++position;
+                }
+            }
+
+            if (DEBUG) {
+                Log.d(TAG, "Item position adjusted for deletion.  Original: " + originalPos
+                        + "  Adjusted: " + position);
+            }
+
+            if (position >= mCursorCount) {
+                throw new IndexOutOfBoundsException("Attempt to retrieve " + position + " of " +
+                        mCursorCount + " items");
+            }
+
+            mCursor.moveToPosition(position);
+            return mCursor;
+        }
+
+        private boolean isEmpty() {
+            return mCursorCount == 0;
+        }
+
+        private boolean isLoading() {
+            return mIsLoading;
+        }
+
+        private List<DocumentInfo> getSelectedDocuments() {
+            Selection sel = getSelection(new Selection());
+            return getDocuments(sel);
+        }
+
+        private List<DocumentInfo> getDocuments(Selection items) {
+            final int size = (items != null) ? items.size() : 0;
+
+            final List<DocumentInfo> docs =  new ArrayList<>(size);
+            for (int i = 0; i < size; i++) {
+                final Cursor cursor = getItem(items.get(i));
+                checkNotNull(cursor, "Cursor cannot be null.");
+                final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+                docs.add(doc);
+            }
+            return docs;
+        }
+
+        @Override
+        public Cursor getCursor() {
+            if (Looper.myLooper() != Looper.getMainLooper()) {
+                throw new IllegalStateException("Can't call getCursor from non-main thread.");
+            }
+            return mCursor;
+        }
+
+        private List<DocumentInfo> getDocumentsMarkedForDeletion() {
+            final int size = mMarkedForDeletion.size();
+            List<DocumentInfo> docs =  new ArrayList<>(size);
+
+            for (int i = 0; i < size; ++i) {
+                final int position = mMarkedForDeletion.keyAt(i);
+                checkState(position < mCursorCount);
+                mCursor.moveToPosition(position);
+                final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(mCursor);
+                docs.add(doc);
+            }
+            return docs;
+        }
+
+        /**
+         * Marks the given files for deletion. This will remove them from the UI. Clients must then
+         * call either {@link #undoDeletion()} or {@link #finalizeDeletion()} to cancel or confirm
+         * the deletion, respectively. Only one deletion operation is allowed at a time.
+         *
+         * @param selected A selection representing the files to delete.
+         */
+        public void markForDeletion(Selection selected) {
+            // Only one deletion operation at a time.
+            checkState(mMarkedForDeletion.size() == 0);
+            // There should never be more to delete than what exists.
+            checkState(mCursorCount >= selected.size());
+
+            final int size = selected.size();
+            for (int i = 0; i < size; ++i) {
+                int position = selected.get(i);
+                if (DEBUG) Log.d(TAG, "Marked position " + position + " for deletion");
+                mMarkedForDeletion.append(position, true);
+                mAdapter.notifyItemRemoved(position);
+            }
+        }
+
+        /**
+         * Cancels an ongoing deletion operation. All files currently marked for deletion will be
+         * unmarked, and restored in the UI.  See {@link #markForDeletion(Selection)}.
+         */
+        public void undoDeletion() {
+            // Iterate over deleted items, temporarily marking them false in the deletion list, and
+            // re-adding them to the UI.
+            final int size = mMarkedForDeletion.size();
+            for (int i = 0; i < size; ++i) {
+                final int position = mMarkedForDeletion.keyAt(i);
+                mMarkedForDeletion.put(position, false);
+                mAdapter.notifyItemInserted(position);
+            }
+
+            // Then, clear the deletion list.
+            mMarkedForDeletion.clear();
+        }
+
+        /**
+         * Finalizes an ongoing deletion operation. All files currently marked for deletion will be
+         * deleted.  See {@link #markForDeletion(Selection)}.
+         */
+        public void finalizeDeletion() {
+            final Context context = getActivity();
+            final ContentResolver resolver = context.getContentResolver();
+            new DeleteFilesTask(resolver).execute();
+        }
+
+        /**
+         * A Task which collects the DocumentInfo for documents that have been marked for deletion,
+         * and actually deletes them.
+         */
+        private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
+            private ContentResolver mResolver;
+
+            public DeleteFilesTask(ContentResolver resolver) {
+                mResolver = resolver;
+            }
+
+            @Override
+            protected List<DocumentInfo> doInBackground(Void... params) {
+                return getDocumentsMarkedForDeletion();
+            }
+
+            @Override
+            protected void onPostExecute(List<DocumentInfo> docs) {
+                boolean hadTrouble = false;
+                for (DocumentInfo doc : docs) {
+                    if (!doc.isDeleteSupported()) {
+                        Log.w(TAG, doc + " could not be deleted.  Skipping...");
+                        hadTrouble = true;
+                        continue;
+                    }
+
+                    ContentProviderClient client = null;
+                    try {
+                        if (DEBUG) Log.d(TAG, "Deleting: " + doc.displayName);
+                        client = DocumentsApplication.acquireUnstableProviderOrThrow(
+                            mResolver, doc.derivedUri.getAuthority());
+                        DocumentsContract.deleteDocument(client, doc.derivedUri);
+                    } catch (Exception e) {
+                        Log.w(TAG, "Failed to delete " + doc);
+                        hadTrouble = true;
+                    } finally {
+                        ContentProviderClient.releaseQuietly(client);
+                    }
+                }
+
+                if (hadTrouble) {
+                    // TODO show which files failed?
+                    Snackbar.make(DirectoryFragment.this.getView(),
+                       R.string.toast_failed_delete,
+                       Snackbar.LENGTH_LONG).show();
+                    if (DEBUG) Log.d(TAG, "Deletion task completed.  Some deletions failed.");
+                } else {
+                    if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
+                }
+                mMarkedForDeletion.clear();
+            }
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Events.java b/packages/DocumentsUI/src/com/android/documentsui/Events.java
index 025b94f..d4c3ba3 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Events.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Events.java
@@ -16,8 +16,11 @@
 
 package com.android.documentsui;
 
+import android.graphics.Point;
+import android.support.v7.widget.RecyclerView;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
+import android.view.View;
 
 /**
  * Utility code for dealing with MotionEvents.
@@ -54,6 +57,20 @@
     }
 
     /**
+     * Returns true if event was triggered by a finger or stylus touch.
+     */
+    static boolean isActionDown(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_DOWN;
+    }
+
+    /**
+     * Returns true if event was triggered by a finger or stylus touch.
+     */
+    static boolean isActionUp(MotionEvent e) {
+        return e.getActionMasked() == MotionEvent.ACTION_UP;
+    }
+
+    /**
      * Returns true if the shift is pressed.
      */
     boolean isShiftPressed(MotionEvent e) {
@@ -66,4 +83,106 @@
     static boolean hasShiftBit(int metaState) {
         return (metaState & KeyEvent.META_SHIFT_ON) != 0;
     }
+
+    /**
+     * A facade over MotionEvent primarily designed to permit for unit testing
+     * of related code.
+     */
+    interface InputEvent {
+        boolean isMouseEvent();
+        boolean isPrimaryButtonPressed();
+        boolean isSecondaryButtonPressed();
+        boolean isShiftKeyDown();
+
+        /** Returns true if the action is the initial press of a mouse or touch. */
+        boolean isActionDown();
+
+        /** Returns true if the action is the final release of a mouse or touch. */
+        boolean isActionUp();
+
+        Point getOrigin();
+
+        /** Returns true if the there is an item under the finger/cursor. */
+        boolean isOverItem();
+
+        /** Returns the adapter position of the item under the finger/cursor. */
+        int getItemPosition();
+    }
+
+    static final class MotionInputEvent implements InputEvent {
+        private final MotionEvent mEvent;
+        private final RecyclerView mView;
+        private final int mPosition;
+
+        public MotionInputEvent(MotionEvent event, RecyclerView view) {
+            mEvent = event;
+            mView = view;
+            View child = mView.findChildViewUnder(mEvent.getX(), mEvent.getY());
+            mPosition = (child != null)
+                    ? mView.getChildAdapterPosition(child)
+                    : RecyclerView.NO_POSITION;
+        }
+
+        @Override
+        public boolean isMouseEvent() {
+            return Events.isMouseEvent(mEvent);
+        }
+
+        @Override
+        public boolean isPrimaryButtonPressed() {
+            return mEvent.isButtonPressed(MotionEvent.BUTTON_PRIMARY);
+        }
+
+        @Override
+        public boolean isSecondaryButtonPressed() {
+            return mEvent.isButtonPressed(MotionEvent.BUTTON_SECONDARY);
+        }
+
+        @Override
+        public boolean isShiftKeyDown() {
+            return Events.hasShiftBit(mEvent.getMetaState());
+        }
+
+        @Override
+        public boolean isActionDown() {
+            return mEvent.getActionMasked() == MotionEvent.ACTION_DOWN;
+        }
+
+        @Override
+        public boolean isActionUp() {
+            return mEvent.getActionMasked() == MotionEvent.ACTION_UP;
+        }
+
+        @Override
+        public Point getOrigin() {
+            return new Point((int) mEvent.getX(), (int) mEvent.getY());
+        }
+
+        @Override
+        public boolean isOverItem() {
+            return getItemPosition() != RecyclerView.NO_POSITION;
+        }
+
+        @Override
+        public int getItemPosition() {
+            return mPosition;
+        }
+
+        @Override
+        public String toString() {
+            return new StringBuilder()
+                    .append("MotionInputEvent {")
+                    .append("isMouseEvent=").append(isMouseEvent())
+                    .append(" isPrimaryButtonPressed=").append(isPrimaryButtonPressed())
+                    .append(" isSecondaryButtonPressed=").append(isSecondaryButtonPressed())
+                    .append(" isShiftKeyDown=").append(isShiftKeyDown())
+                    .append(" isActionDown=").append(isActionDown())
+                    .append(" isActionUp=").append(isActionUp())
+                    .append(" getOrigin=").append(getOrigin())
+                    .append(" isOverItem=").append(isOverItem())
+                    .append(" getItemPosition=").append(getItemPosition())
+                    .append("}")
+                    .toString();
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index e972566..c7afc04 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -16,11 +16,16 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.Events.isMouseEvent;
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
 
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.Adapter;
@@ -36,10 +41,9 @@
 import android.view.GestureDetector.OnGestureListener;
 import android.view.MotionEvent;
 import android.view.View;
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.annotation.VisibleForTesting;
+
+import com.android.documentsui.Events.InputEvent;
+import com.android.documentsui.Events.MotionInputEvent;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -59,7 +63,6 @@
     public static final int MODE_SINGLE = 1;
 
     private static final String TAG = "MultiSelectManager";
-    private static final boolean DEBUG = false;
 
     private final Selection mSelection = new Selection();
 
@@ -72,7 +75,7 @@
     private Adapter<?> mAdapter;
     private MultiSelectHelper mHelper;
     private boolean mSingleSelect;
-    private BandSelectManager mBandSelectManager;
+    private BandSelectManager mBandManager;
 
     /**
      * @param recyclerView
@@ -89,17 +92,19 @@
                 new RuntimeRecyclerViewHelper(recyclerView),
                 mode);
 
-        mBandSelectManager = new BandSelectManager((RuntimeRecyclerViewHelper) mHelper);
+        mBandManager = new BandSelectManager((RuntimeRecyclerViewHelper) mHelper);
 
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
                     @Override
                     public boolean onSingleTapUp(MotionEvent e) {
-                        return MultiSelectManager.this.onSingleTapUp(e);
+                        return MultiSelectManager.this.onSingleTapUp(
+                                new MotionInputEvent(e, recyclerView));
                     }
                     @Override
                     public void onLongPress(MotionEvent e) {
-                        MultiSelectManager.this.onLongPress(e);
+                        MultiSelectManager.this.onLongPress(
+                                new MotionInputEvent(e, recyclerView));
                     }
                 };
 
@@ -112,17 +117,39 @@
 
         recyclerView.addOnItemTouchListener(
                 new RecyclerView.OnItemTouchListener() {
+                    @Override
                     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                         detector.onTouchEvent(e);
 
-                        // Only intercept the event if it was a mouse-based band selection.
-                        return isMouseEvent(e) && (mBandSelectManager.mIsActive ||
-                                e.getActionMasked() != MotionEvent.ACTION_UP);
+                        // b/23793622 notes the fact that we *never* receiver ACTION_DOWN
+                        // events in onTouchEvent. Where it not for this issue, we'd
+                        // push start handling down into handleInputEvent.
+                        if (mBandManager.shouldStart(e)) {
+                            // endBandSelect is handled in handleInputEvent.
+                            mBandManager.startBandSelect(
+                                    new Point((int) e.getX(), (int) e.getY()));
+                        } else if (mBandManager.isActive()
+                                && Events.isMouseEvent(e)
+                                && Events.isActionUp(e)) {
+                            // Same issue here w b/23793622. The ACTION_UP event
+                            // is only evert dispatched to onTouchEvent when
+                            // there is some associated motion. If a user taps
+                            // mouse, but doesn't move, then band select gets
+                            // started BUT not ended. Causing phantom
+                            // bands to appear when the user later clicks to start
+                            // band select.
+                            mBandManager.handleInputEvent(
+                                    new MotionInputEvent(e, recyclerView));
+                        }
+                        return mBandManager.isActive();
                     }
+
+                    @Override
                     public void onTouchEvent(RecyclerView rv, MotionEvent e) {
-                        checkState(isMouseEvent(e));
-                        mBandSelectManager.processMotionEvent(e);
+                        mBandManager.handleInputEvent(
+                                new MotionInputEvent(e, recyclerView));
                     }
+                    @Override
                     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
                 });
     }
@@ -184,13 +211,13 @@
 
     /**
      * Returns a Selection object that provides a live view
-     * on the current selection. Callers wishing to get
+     * on the current selection.
      *
-     * @see #getSelectionSnapshot() on how to get a snapshot
+     * @see #getSelection(Selection) on how to get a snapshot
      *     of the selection that will not reflect future changes
      *     to selection.
      *
-     * @return The current seleciton.
+     * @return The current selection.
      */
     public Selection getSelection() {
         return mSelection;
@@ -250,6 +277,10 @@
         notifySelectionChanged();
     }
 
+    public void handleLayoutChanged() {
+        mBandManager.handleLayoutChanged();
+    }
+
     /**
      * Clears the selection, without notifying anyone.
      */
@@ -271,71 +302,37 @@
         }
     }
 
-    private void onLongPress(MotionEvent e) {
+    @VisibleForTesting
+    void onLongPress(InputEvent input) {
         if (DEBUG) Log.d(TAG, "Handling long press event.");
 
-        int position = mHelper.findEventPosition(e);
-        if (position == RecyclerView.NO_POSITION) {
-            if (DEBUG) Log.i(TAG, "View is null. Cannot handle tap event.");
+        if (!input.isOverItem()) {
+            if (DEBUG) Log.i(TAG, "Cannot handle tap. No adapter position available.");
         }
 
-        onLongPress(position, e.getMetaState());
+        handleAdapterEvent(input);
     }
 
-    /**
-     * TODO: Roll this back into {@link #onLongPress(MotionEvent)} once MotionEvent
-     * can be mocked.
-     *
-     * @param position
-     * @param metaState as returned from {@link MotionEvent#getMetaState()}.
-     * @hide
-     */
     @VisibleForTesting
-    void onLongPress(int position, int metaState) {
-        if (position == RecyclerView.NO_POSITION) {
-            if (DEBUG) Log.i(TAG, "View is null. Cannot handle tap event.");
-        }
-
-        handlePositionChanged(position, metaState);
-    }
-
-    /**
-     * @param e
-     * @return true if the event was consumed.
-     */
-    private boolean onSingleTapUp(MotionEvent e) {
-        if (DEBUG) Log.d(TAG, "Handling tap event.");
-        return onSingleTapUp(mHelper.findEventPosition(e), e.getMetaState(), e.getToolType(0));
-    }
-
-    /**
-     * TODO: Roll this into {@link #onSingleTapUp(MotionEvent)} once MotionEvent
-     * can be mocked.
-     *
-     * @param position
-     * @param metaState as returned from {@link MotionEvent#getMetaState()}.
-     * @param toolType
-     * @return true if the event was consumed.
-     * @hide
-     */
-    @VisibleForTesting
-    boolean onSingleTapUp(int position, int metaState, int toolType) {
+    boolean onSingleTapUp(InputEvent input) {
+        if (DEBUG) Log.d(TAG, "Processing tap event.");
         if (mSelection.isEmpty()) {
             // if this is a mouse click on an item, start selection mode.
-            if (position != RecyclerView.NO_POSITION && Events.isMouseType(toolType)) {
-                toggleSelection(position);
+            // TODO:  && input.isPrimaryButtonPressed(), but it is returning false.
+            if (input.isOverItem() && input.isMouseEvent()) {
+                toggleSelection(input.getItemPosition());
             }
             return false;
         }
 
-        if (position == RecyclerView.NO_POSITION) {
-            if (DEBUG) Log.d(TAG, "View is null. Canceling selection.");
+        if (!input.isOverItem()) {
+            if (DEBUG) Log.d(TAG, "Activity has no position. Canceling selection.");
             clearSelection();
             return false;
         }
 
-        handlePositionChanged(position, metaState);
-        return false;
+        handleAdapterEvent(input);
+        return true;
     }
 
     /**
@@ -343,15 +340,15 @@
      * held down, this performs a range select; otherwise, it simply toggles the item's selection
      * state.
      */
-    private void handlePositionChanged(int position, int metaState) {
-        if (Events.hasShiftBit(metaState) && mRanger != null) {
-            mRanger.snapSelection(position);
+    private void handleAdapterEvent(InputEvent input) {
+        if (mRanger != null && input.isShiftKeyDown()) {
+            mRanger.snapSelection(input.getItemPosition());
 
             // We're being lazy here notifying even when something might not have changed.
             // To make this more correct, we'd need to update the Ranger class to return
             // information about what has changed.
             notifySelectionChanged();
-        } else if (toggleSelection(position)) {
+        } else if (toggleSelection(input.getItemPosition())) {
             notifySelectionChanged();
         }
     }
@@ -1171,12 +1168,12 @@
         private static final int NOT_SET = -1;
 
         private final BandManagerHelper mHelper;
+        private final Runnable mModelBuilder;
 
-        private boolean mIsActive;
-        private Point mOrigin;
-        private Point mPointer;
-        private Rect mBounds;
-        private BandSelectModel mModel;
+        @Nullable private Rect mBounds;
+        @Nullable private Point mCurrentPosition;
+        @Nullable private Point mOrigin;
+        @Nullable private BandSelectModel mModel;
 
         // The time at which the current band selection-induced scroll began. If no scroll is in
         // progress, the value is NOT_SET.
@@ -1184,39 +1181,70 @@
         private final Runnable mViewScroller = new ViewScroller();
 
         public <T extends BandManagerHelper & BandModelHelper>
-                BandSelectManager(T helper) {
+                BandSelectManager(final T helper) {
             mHelper = helper;
             mHelper.addOnScrollListener(this);
-            mModel = new BandSelectModel(helper);
-            mModel.addOnSelectionChangedListener(this);
+
+            mModelBuilder = new Runnable() {
+                @Override
+                public void run() {
+                    mModel = new BandSelectModel(helper);
+                    mModel.addOnSelectionChangedListener(BandSelectManager.this);
+                }
+            };
+        }
+
+        private boolean isActive() {
+            return mModel != null;
+        }
+
+        /**
+         * Handle a change in layout by cleaning up and getting rid of the old model and creating
+         * a new model which will track the new layout.
+         */
+        public void handleLayoutChanged() {
+            if (mModel != null) {
+                mModel.removeOnSelectionChangedListener(this);
+                mModel.stopListening();
+
+                // build a new model, all fresh and happy.
+                mModelBuilder.run();
+            }
+        }
+
+        boolean shouldStart(MotionEvent e) {
+            return !isActive()
+                    && Events.isMouseEvent(e)  // a mouse
+                    && Events.isActionDown(e)  // the initial button press
+                    && mHelper.findEventPosition(e) == RecyclerView.NO_ID;  // in empty space
+        }
+
+        boolean shouldStop(InputEvent input) {
+            return isActive()
+                    && input.isMouseEvent()
+                    && input.isActionUp();
         }
 
         /**
          * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
-         * @param e
+         * @param input
          */
-        private void processMotionEvent(MotionEvent e) {
-            if (!isMouseEvent(e)) {
+        private void handleInputEvent(InputEvent input) {
+            checkArgument(input.isMouseEvent());
+
+            if (shouldStop(input)) {
+                mBandManager.endBandSelect();
                 return;
             }
 
-            if (mIsActive && e.getActionMasked() == MotionEvent.ACTION_UP) {
-                endBandSelect();
+            // We shouldn't get any events in this method when band select is not active,
+            // but it turns some guests show up late to the party.
+            if (!isActive()) {
                 return;
             }
 
-            mPointer = new Point((int) e.getX(), (int) e.getY());
-            if (!mIsActive) {
-                // Only start a band select if the pointer is in margins between items, not
-                // actually within an item's bounds.
-                if (mHelper.findEventPosition(e) != RecyclerView.NO_POSITION) {
-                    return;
-                }
-                startBandSelect();
-            } else {
-                mModel.resizeSelection(mPointer);
-            }
-
+            mCurrentPosition = input.getOrigin();
+            mModel.resizeSelection(input.getOrigin());
             scrollViewIfNecessary();
             resizeBandSelectRectangle();
         }
@@ -1224,12 +1252,11 @@
         /**
          * Starts band select by adding the drawable to the RecyclerView's overlay.
          */
-        private void startBandSelect() {
-            if (DEBUG) {
-                Log.d(TAG, "Starting band select from (" + mPointer.x + "," + mPointer.y + ").");
-            }
-            mIsActive = true;
-            mOrigin = new Point(mPointer.x, mPointer.y);
+        private void startBandSelect(Point origin) {
+            if (DEBUG) Log.d(TAG, "Starting band select @ " + origin);
+
+            mOrigin = origin;
+            mModelBuilder.run();  // Creates a new selection model.
             mModel.startSelection(mOrigin);
         }
 
@@ -1247,10 +1274,10 @@
          * two opposite corners of the selection.
          */
         private void resizeBandSelectRectangle() {
-            mBounds = new Rect(Math.min(mOrigin.x, mPointer.x),
-                    Math.min(mOrigin.y, mPointer.y),
-                    Math.max(mOrigin.x, mPointer.x),
-                    Math.max(mOrigin.y, mPointer.y));
+            mBounds = new Rect(Math.min(mOrigin.x, mCurrentPosition.x),
+                    Math.min(mOrigin.y, mCurrentPosition.y),
+                    Math.max(mOrigin.x, mCurrentPosition.x),
+                    Math.max(mOrigin.y, mCurrentPosition.y));
             mHelper.drawBand(mBounds);
         }
 
@@ -1259,14 +1286,20 @@
          */
         private void endBandSelect() {
             if (DEBUG) Log.d(TAG, "Ending band select.");
-            mIsActive = false;
+
             mHelper.hideBand();
             mSelection.applyProvisionalSelection();
             mModel.endSelection();
             int firstSelected = mModel.getPositionNearestOrigin();
-            if (firstSelected != BandSelectModel.NOT_SET) {
+            if (!mSelection.contains(firstSelected)) {
+                Log.w(TAG, "First selected by band is NOT in selection!");
+                // Sadly this is really happening. Need to figure out what's going on.
+            } else if (firstSelected != BandSelectModel.NOT_SET) {
                 setSelectionFocusBegin(firstSelected);
             }
+
+            mModel = null;
+            mOrigin = null;
         }
 
         @Override
@@ -1295,13 +1328,13 @@
                 // that one additional pixel is added here so that the view still scrolls when the
                 // pointer is exactly at the top or bottom.
                 int pixelsPastView = 0;
-                if (mPointer.y <= 0) {
-                    pixelsPastView = mPointer.y - 1;
-                } else if (mPointer.y >= mHelper.getHeight() - 1) {
-                    pixelsPastView = mPointer.y - mHelper.getHeight() + 1;
+                if (mCurrentPosition.y <= 0) {
+                    pixelsPastView = mCurrentPosition.y - 1;
+                } else if (mCurrentPosition.y >= mHelper.getHeight() - 1) {
+                    pixelsPastView = mCurrentPosition.y - mHelper.getHeight() + 1;
                 }
 
-                if (!mIsActive || pixelsPastView == 0) {
+                if (!isActive() || pixelsPastView == 0) {
                     // If band selection is inactive, or if it is active but not at the edge of the
                     // view, no scrolling is necessary.
                     mScrollStartTime = NOT_SET;
@@ -1387,7 +1420,7 @@
 
         @Override
         public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
-            if (!mIsActive) {
+            if (!isActive()) {
                 return;
             }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index b414ee3..0c1ebc1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -16,9 +16,19 @@
 
 package com.android.documentsui;
 
+import android.content.Context;
+
 /**
  * @hide
  */
 public final class Shared {
+    public static final boolean DEBUG = false;
     public static final String TAG = "Documents";
+
+    /**
+     * Generates a formatted quantity string.
+     */
+    public static final String getQuantityString(Context context, int resourceId, int quantity) {
+        return context.getResources().getQuantityString(resourceId, quantity, quantity);
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
index b82251c..337064c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
@@ -16,11 +16,11 @@
 
 package com.android.documentsui;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 import android.support.v7.widget.RecyclerView;
 import android.util.SparseBooleanArray;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -52,7 +52,6 @@
     private MultiSelectManager mManager;
     private TestAdapter mAdapter;
     private TestCallback mCallback;
-
     private EventHelper mEventHelper;
 
     @Before
@@ -72,14 +71,14 @@
 
     @Test
     public void mouseClick_ShiftClickExtendsSelection() {
-        click(7);
+        longPress(7);
         shiftClick(11);
         assertRangeSelection(7, 11);
     }
 
     @Test
     public void mouseClick_NoPosition_ClearsSelection() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         click(11);
         click(RecyclerView.NO_POSITION);
         assertSelection();
@@ -95,27 +94,27 @@
 
     @Test
     public void longPress_StartsSelectionMode() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         assertSelection(7);
     }
 
     @Test
     public void longPress_SecondPressExtendsSelection() {
-        mManager.onLongPress(7, 0);
-        mManager.onLongPress(99, 0);
+        longPress(7);
+        longPress(99);
         assertSelection(7, 99);
     }
 
     @Test
     public void singleTapUp_UnselectsSelectedItem() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         tap(7);
         assertSelection();
     }
 
     @Test
     public void singleTapUp_NoPosition_ClearsSelection() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         tap(11);
         tap(RecyclerView.NO_POSITION);
         assertSelection();
@@ -123,7 +122,7 @@
 
     @Test
     public void singleTapUp_ExtendsSelection() {
-        mManager.onLongPress(99, 0);
+        longPress(99);
         tap(7);
         tap(13);
         tap(129899);
@@ -132,21 +131,21 @@
 
     @Test
     public void singleTapUp_ShiftCreatesRangeSelection() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         shiftTap(17);
         assertRangeSelection(7, 17);
     }
 
     @Test
     public void singleTapUp_ShiftCreatesRangeSeletion_Backwards() {
-        mManager.onLongPress(17, 0);
+        longPress(17);
         shiftTap(7);
         assertRangeSelection(7, 17);
     }
 
     @Test
     public void singleTapUp_SecondShiftClickExtendsSelection() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         shiftTap(11);
         shiftTap(17);
         assertRangeSelection(7, 17);
@@ -154,7 +153,7 @@
 
     @Test
     public void singleTapUp_MultipleContiguousRangesSelected() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         shiftTap(11);
         tap(20);
         shiftTap(25);
@@ -165,7 +164,7 @@
 
     @Test
     public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         shiftTap(17);
         shiftTap(10);
         assertRangeSelection(7, 10);
@@ -173,7 +172,7 @@
 
     @Test
     public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
-        mManager.onLongPress(17, 0);
+        mManager.onLongPress(TestInputEvent.tap(17));
         shiftTap(7);
         shiftTap(14);
         assertRangeSelection(14, 17);
@@ -182,7 +181,7 @@
 
     @Test
     public void singleTapUp_ShiftReversesSelectionDirection() {
-        mManager.onLongPress(7, 0);
+        longPress(7);
         shiftTap(17);
         shiftTap(0);
         assertRangeSelection(0, 7);
@@ -192,7 +191,7 @@
     public void singleSelectMode() {
         mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
-        tap(20);
+        longPress(20);
         tap(13);
         assertSelection(13);
     }
@@ -201,7 +200,7 @@
     public void singleSelectMode_ShiftTap() {
         mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
-        tap(13);
+        longPress(13);
         shiftTap(20);
         assertSelection(20);
     }
@@ -236,20 +235,24 @@
         assertSelection(2, 3, 4);
     }
 
+    private void longPress(int position) {
+        mManager.onLongPress(TestInputEvent.tap(position));
+    }
+
     private void tap(int position) {
-        mManager.onSingleTapUp(position, 0, MotionEvent.TOOL_TYPE_MOUSE);
+        mManager.onSingleTapUp(TestInputEvent.tap(position));
     }
 
     private void shiftTap(int position) {
-        mManager.onSingleTapUp(position, KeyEvent.META_SHIFT_ON, MotionEvent.TOOL_TYPE_FINGER);
+        mManager.onSingleTapUp(TestInputEvent.shiftTap(position));
     }
 
     private void click(int position) {
-        mManager.onSingleTapUp(position, 0, MotionEvent.TOOL_TYPE_MOUSE);
+        mManager.onSingleTapUp(TestInputEvent.click(position));
     }
 
     private void shiftClick(int position) {
-        mManager.onSingleTapUp(position, KeyEvent.META_SHIFT_ON, MotionEvent.TOOL_TYPE_MOUSE);
+        mManager.onSingleTapUp(TestInputEvent.shiftClick(position));
     }
 
     private void assertSelected(int... expected) {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java b/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java
new file mode 100644
index 0000000..e83f9e0
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/TestInputEvent.java
@@ -0,0 +1,90 @@
+package com.android.documentsui;
+
+import android.graphics.Point;
+import android.support.v7.widget.RecyclerView;
+
+class TestInputEvent implements Events.InputEvent {
+
+    public boolean mouseEvent;
+    public boolean primaryButtonPressed;
+    public boolean secondaryButtonPressed;
+    public boolean shiftKeyDow;
+    public boolean actionDown;
+    public boolean actionUp;
+    public Point location;
+    public int position = Integer.MIN_VALUE;
+
+    public TestInputEvent() {}
+
+    public TestInputEvent(int position) {
+        this.position = position;
+    }
+
+    @Override
+    public boolean isMouseEvent() {
+        return mouseEvent;
+    }
+
+    @Override
+    public boolean isPrimaryButtonPressed() {
+        return primaryButtonPressed;
+    }
+
+    @Override
+    public boolean isSecondaryButtonPressed() {
+        return secondaryButtonPressed;
+    }
+
+    @Override
+    public boolean isShiftKeyDown() {
+        return shiftKeyDow;
+    }
+
+    @Override
+    public boolean isActionDown() {
+        return actionDown;
+    }
+
+    @Override
+    public boolean isActionUp() {
+        return actionUp;
+    }
+
+    @Override
+    public Point getOrigin() {
+        return location;
+    }
+
+    @Override
+    public boolean isOverItem() {
+        return position != Integer.MIN_VALUE && position != RecyclerView.NO_POSITION;
+    }
+
+    @Override
+    public int getItemPosition() {
+        return position;
+    }
+
+    public static TestInputEvent tap(int position) {
+        return new TestInputEvent(position);
+    }
+
+    public static TestInputEvent shiftTap(int position) {
+        TestInputEvent e = new TestInputEvent(position);
+        e.shiftKeyDow = true;
+        return e;
+    }
+
+    public static TestInputEvent click(int position) {
+        TestInputEvent e = new TestInputEvent(position);
+        e.mouseEvent = true;
+        return e;
+    }
+
+    public static TestInputEvent shiftClick(int position) {
+        TestInputEvent e = new TestInputEvent(position);
+        e.mouseEvent = true;
+        e.shiftKeyDow = true;
+        return e;
+    }
+}
diff --git a/packages/InputDevices/res/values-uz-rUZ/strings.xml b/packages/InputDevices/res/values-uz-rUZ/strings.xml
index 0a99ad3..3b6772b 100644
--- a/packages/InputDevices/res/values-uz-rUZ/strings.xml
+++ b/packages/InputDevices/res/values-uz-rUZ/strings.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="8016145283189546017">"Kiruvchi qurilmalar"</string>
+    <string name="app_label" msgid="8016145283189546017">"Kiritish qurilmalari"</string>
     <string name="keyboard_layouts_label" msgid="6688773268302087545">"Android klaviaturasi"</string>
     <string name="keyboard_layout_english_uk_label" msgid="6664258463319999632">"Inglizcha (BQ)"</string>
     <string name="keyboard_layout_english_us_label" msgid="8994890249649106291">"Inglizcha (AQSH)"</string>
diff --git a/packages/Keyguard/res/values-pl/strings.xml b/packages/Keyguard/res/values-pl/strings.xml
index 8fd2086..04930c5 100644
--- a/packages/Keyguard/res/values-pl/strings.xml
+++ b/packages/Keyguard/res/values-pl/strings.xml
@@ -141,5 +141,5 @@
       <item quantity="other">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_1">%d</xliff:g> godziny. Potwierdź hasło.</item>
       <item quantity="one">Urządzenie nie zostało odblokowane od <xliff:g id="NUMBER_0">%d</xliff:g> godziny. Potwierdź hasło.</item>
     </plurals>
-    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nie rozpoznano"</string>
+    <string name="fingerprint_not_recognized" msgid="2690661881608146617">"Nie rozpoznano odcisku palca."</string>
 </resources>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index ce2d11a..f51e10f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -64,7 +64,7 @@
 
     @Override
     protected void resetState() {
-        mPasswordEntry.setEnabled(true);
+        setPasswordEntryEnabled(true);
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index fc6117f..b752c9b 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
@@ -472,6 +473,10 @@
         }
     }
 
+    private void handleFingerprintLockoutReset() {
+        updateFingerprintListeningState();
+    }
+
     private void setFingerprintRunningState(int fingerprintRunningState) {
         boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
         boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
@@ -681,6 +686,14 @@
         }
     };
 
+    private final FingerprintManager.LockoutResetCallback mLockoutResetCallback
+            = new FingerprintManager.LockoutResetCallback() {
+        @Override
+        public void onLockoutReset() {
+            handleFingerprintLockoutReset();
+        }
+    };
+
     private FingerprintManager.AuthenticationCallback mAuthenticationCallback
             = new AuthenticationCallback() {
 
@@ -1003,6 +1016,9 @@
 
         mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
         updateFingerprintListeningState();
+        if (mFpm != null) {
+            mFpm.addLockoutResetCallback(mLockoutResetCallback);
+        }
     }
 
     private void updateFingerprintListeningState() {
@@ -1332,9 +1348,7 @@
      */
     private void handleKeyguardReset() {
         if (DEBUG) Log.d(TAG, "handleKeyguardReset");
-        if (!isUnlockingWithFingerprintAllowed()) {
-            updateFingerprintListeningState();
-        }
+        updateFingerprintListeningState();
     }
 
     /**
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
new file mode 100644
index 0000000..b5694b7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/CursorHelper.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.database.MatrixCursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsContract.Document;
+
+import java.util.Date;
+
+final class CursorHelper {
+    static final int DUMMY_HANDLE_FOR_ROOT = 0;
+
+    private CursorHelper() {
+    }
+
+    static void addToCursor(MtpRoot root, MatrixCursor.RowBuilder builder) {
+        final Identifier identifier = new Identifier(
+                root.mDeviceId, root.mStorageId, DUMMY_HANDLE_FOR_ROOT);
+        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+        builder.add(Document.COLUMN_DISPLAY_NAME, root.mDescription);
+        builder.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+        builder.add(Document.COLUMN_LAST_MODIFIED, null);
+        builder.add(Document.COLUMN_FLAGS, 0);
+        builder.add(Document.COLUMN_SIZE,
+                (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE));
+    }
+
+    static void addToCursor(MtpObjectInfo objectInfo, Identifier rootIdentifier,
+            MatrixCursor.RowBuilder builder) {
+        final Identifier identifier = new Identifier(
+                rootIdentifier.mDeviceId, rootIdentifier.mStorageId, objectInfo.getObjectHandle());
+        final String mimeType = formatTypeToMimeType(objectInfo.getFormat());
+
+        int flag = 0;
+        if (objectInfo.getProtectionStatus() == 0) {
+            flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                    DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+            if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR) {
+                flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
+            }
+        }
+        if (objectInfo.getThumbCompressedSize() > 0) {
+            flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
+        }
+
+        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
+        builder.add(Document.COLUMN_DISPLAY_NAME, objectInfo.getName());
+        builder.add(Document.COLUMN_MIME_TYPE, mimeType);
+        builder.add(
+                Document.COLUMN_LAST_MODIFIED,
+                objectInfo.getDateModified() != 0 ? objectInfo.getDateModified() : null);
+        builder.add(Document.COLUMN_FLAGS, flag);
+        builder.add(Document.COLUMN_SIZE, objectInfo.getCompressedSize());
+    }
+
+    static String formatTypeToMimeType(int format) {
+        // TODO: Add complete list of mime types.
+        switch (format) {
+            case MtpConstants.FORMAT_ASSOCIATION:
+                return DocumentsContract.Document.MIME_TYPE_DIR;
+            case MtpConstants.FORMAT_MP3:
+                return "audio/mp3";
+            case MtpConstants.FORMAT_EXIF_JPEG:
+                return "image/jpeg";
+            default:
+                return "application/octet-stream";
+        }
+    }
+
+    static int mimeTypeToFormatType(String mimeType) {
+        // TODO: Add complete list of mime types.
+        switch (mimeType.toLowerCase()) {
+            case Document.MIME_TYPE_DIR:
+                return MtpConstants.FORMAT_ASSOCIATION;
+            case "audio/mp3":
+                return MtpConstants.FORMAT_MP3;
+            case "image/jpeg":
+                return MtpConstants.FORMAT_EXIF_JPEG;
+            default:
+                return MtpConstants.FORMAT_UNDEFINED;
+        }
+    }
+}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
index c430def..d4c4331 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/DocumentLoader.java
@@ -19,6 +19,7 @@
 import android.content.ContentResolver;
 import android.database.Cursor;
 import android.database.MatrixCursor;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Process;
@@ -34,6 +35,7 @@
  * Loader for MTP document.
  * At the first request, the loader returns only first NUM_INITIAL_ENTRIES. Then it launches
  * background thread to load the rest documents and caches its result for next requests.
+ * TODO: Rename this class to ObjectInfoLoader
  */
 class DocumentLoader {
     static final int NUM_INITIAL_ENTRIES = 10;
@@ -50,13 +52,13 @@
         mResolver = resolver;
     }
 
-    private static MtpDocument[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
+    private static MtpObjectInfo[] loadDocuments(MtpManager manager, int deviceId, int[] handles)
             throws IOException {
-        final MtpDocument[] documents = new MtpDocument[handles.length];
+        final MtpObjectInfo[] objectInfos = new MtpObjectInfo[handles.length];
         for (int i = 0; i < handles.length; i++) {
-            documents[i] = manager.getDocument(deviceId, handles[i]);
+            objectInfos[i] = manager.getObjectInfo(deviceId, handles[i]);
         }
-        return documents;
+        return objectInfos;
     }
 
     synchronized Cursor queryChildDocuments(String[] columnNames, Identifier parent)
@@ -66,7 +68,7 @@
             int parentHandle = parent.mObjectHandle;
             // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
             // getObjectHandles if we would like to obtain children under the root.
-            if (parentHandle == MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+            if (parentHandle == CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
                 parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
             }
             task = new LoaderTask(parent, mMtpManager.getObjectHandles(
@@ -89,14 +91,18 @@
         return task.createCursor(mResolver, columnNames);
     }
 
-    synchronized void clearCache(int deviceId) {
+    synchronized void clearTasks(int deviceId) {
         mTaskList.clearTaskForDevice(deviceId);
     }
 
-    synchronized void clearCache() {
+    synchronized void clearCompletedTasks() {
         mTaskList.clearCompletedTask();
     }
 
+    synchronized void clearTask(Identifier parentIdentifier) {
+        mTaskList.clearTask(parentIdentifier);
+    }
+
     private class BackgroundLoaderThread extends Thread {
         @Override
         public void run() {
@@ -114,16 +120,16 @@
                     deviceId = task.mIdentifier.mDeviceId;
                     handles = task.getUnloadedObjectHandles(NUM_LOADING_ENTRIES);
                 }
-                MtpDocument[] documents;
+                MtpObjectInfo[] objectInfos;
                 try {
-                    documents = loadDocuments(mMtpManager, deviceId, handles);
+                    objectInfos = loadDocuments(mMtpManager, deviceId, handles);
                 } catch (IOException exception) {
-                    documents = null;
+                    objectInfos = null;
                     Log.d(MtpDocumentsProvider.TAG, exception.getMessage());
                 }
                 synchronized (DocumentLoader.this) {
-                    if (documents != null) {
-                        task.fillDocuments(documents);
+                    if (objectInfos != null) {
+                        task.fillDocuments(objectInfos);
                         final boolean shouldNotify =
                                 task.mLastNotified.getTime() <
                                 new Date().getTime() - NOTIFY_PERIOD_MS ||
@@ -177,19 +183,30 @@
                 }
             }
         }
+
+        void clearTask(Identifier parentIdentifier) {
+            for (int i = 0; i < size(); i++) {
+                final LoaderTask task = get(i);
+                if (task.mIdentifier.mDeviceId == parentIdentifier.mDeviceId &&
+                        task.mIdentifier.mObjectHandle == parentIdentifier.mObjectHandle) {
+                    remove(i);
+                    return;
+                }
+            }
+        }
     }
 
     private static class LoaderTask {
         final Identifier mIdentifier;
         final int[] mObjectHandles;
-        final MtpDocument[] mDocuments;
+        final MtpObjectInfo[] mObjectInfos;
         Date mLastNotified;
         int mNumLoaded;
 
         LoaderTask(Identifier identifier, int[] objectHandles) {
             mIdentifier = identifier;
             mObjectHandles = objectHandles;
-            mDocuments = new MtpDocument[mObjectHandles.length];
+            mObjectInfos = new MtpObjectInfo[mObjectHandles.length];
             mNumLoaded = 0;
             mLastNotified = new Date();
         }
@@ -199,7 +216,7 @@
             final Identifier rootIdentifier = new Identifier(
                     mIdentifier.mDeviceId, mIdentifier.mStorageId);
             for (int i = 0; i < mNumLoaded; i++) {
-                mDocuments[i].addToCursor(rootIdentifier, cursor.newRow());
+                CursorHelper.addToCursor(mObjectInfos[i], rootIdentifier, cursor.newRow());
             }
             final Bundle extras = new Bundle();
             extras.putBoolean(DocumentsContract.EXTRA_LOADING, !completed());
@@ -209,7 +226,7 @@
         }
 
         boolean completed() {
-            return mNumLoaded == mDocuments.length;
+            return mNumLoaded == mObjectInfos.length;
         }
 
         int[] getUnloadedObjectHandles(int count) {
@@ -224,9 +241,9 @@
             mLastNotified = new Date();
         }
 
-        void fillDocuments(MtpDocument[] documents) {
-            for (int i = 0; i < documents.length; i++) {
-                mDocuments[mNumLoaded++] = documents[i];
+        void fillDocuments(MtpObjectInfo[] objectInfos) {
+            for (int i = 0; i < objectInfos.length; i++) {
+                mObjectInfos[mNumLoaded++] = objectInfos[i];
             }
         }
 
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
index bd0c837..ae29f52 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/Identifier.java
@@ -41,7 +41,7 @@
 
 
     Identifier(int deviceId, int storageId) {
-        this(deviceId, storageId, MtpDocument.DUMMY_HANDLE_FOR_ROOT);
+        this(deviceId, storageId, CursorHelper.DUMMY_HANDLE_FOR_ROOT);
     }
 
     Identifier(int deviceId, int storageId, int objectHandle) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
deleted file mode 100644
index 7126694..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mtp;
-
-import android.database.MatrixCursor;
-import android.mtp.MtpObjectInfo;
-import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Document;
-
-import java.util.Date;
-
-class MtpDocument {
-    static final int DUMMY_HANDLE_FOR_ROOT = 0;
-
-    private final int mObjectHandle;
-    private final int mFormat;
-    private final String mName;
-    private final Date mDateModified;
-    private final int mSize;
-    private final int mThumbSize;
-    private final boolean mReadOnly;
-
-    /**
-     * Constructor for root document.
-     */
-    MtpDocument(MtpRoot root) {
-        this(DUMMY_HANDLE_FOR_ROOT,
-             0x3001,  // Directory.
-             root.mDescription,
-             null,    // Unknown name.
-             (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
-             0,       // Total size.
-             true);   // Writable.
-    }
-
-    MtpDocument(MtpObjectInfo objectInfo) {
-        this(objectInfo.getObjectHandle(),
-             objectInfo.getFormat(),
-             objectInfo.getName(),
-             objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
-             objectInfo.getCompressedSize(),
-             objectInfo.getThumbCompressedSize(),
-             objectInfo.getProtectionStatus() != 0);
-    }
-
-    MtpDocument(int objectHandle,
-                int format,
-                String name,
-                Date dateModified,
-                int size,
-                int thumbSize,
-                boolean readOnly) {
-        this.mObjectHandle = objectHandle;
-        this.mFormat = format;
-        this.mName = name;
-        this.mDateModified = dateModified;
-        this.mSize = size;
-        this.mThumbSize = thumbSize;
-        this.mReadOnly = readOnly;
-    }
-
-    void addToCursor(Identifier rootIdentifier, MatrixCursor.RowBuilder builder) {
-        final Identifier identifier = new Identifier(
-                rootIdentifier.mDeviceId, rootIdentifier.mStorageId, mObjectHandle);
-
-        int flag = 0;
-        if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
-            flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE;
-            if (mThumbSize > 0) {
-                flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
-            }
-        }
-
-        builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
-        builder.add(Document.COLUMN_DISPLAY_NAME, mName);
-        builder.add(Document.COLUMN_MIME_TYPE, formatTypeToMimeType(mFormat));
-        builder.add(
-                Document.COLUMN_LAST_MODIFIED,
-                mDateModified != null ? mDateModified.getTime() : null);
-        builder.add(Document.COLUMN_FLAGS, flag);
-        builder.add(Document.COLUMN_SIZE, mSize);
-    }
-
-    static String formatTypeToMimeType(int format) {
-        // TODO: Add complete list of mime types.
-        switch (format) {
-            case 0x3001:
-                return DocumentsContract.Document.MIME_TYPE_DIR;
-            case 0x3009:
-                return "audio/mp3";
-            case 0x3801:
-                return "image/jpeg";
-            default:
-                return "application/octet-stream";
-        }
-    }
-
-    static int mimeTypeToFormatType(String mimeType) {
-        // TODO: Add complete list of mime types.
-        switch (mimeType.toLowerCase()) {
-            case Document.MIME_TYPE_DIR:
-                return 0x3001;
-            case "audio/mp3":
-                return 0x3009;
-            case "image/jpeg":
-                return 0x3801;
-            default:
-                return 0x3000;  // Undefined object.
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 031cc07..78ed161 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -21,11 +21,12 @@
 import android.database.Cursor;
 import android.database.MatrixCursor;
 import android.graphics.Point;
+import android.mtp.MtpObjectInfo;
 import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
 import android.provider.DocumentsProvider;
 import android.util.Log;
 
@@ -116,37 +117,37 @@
         }
         final Identifier identifier = Identifier.createFromDocumentId(documentId);
 
-        MtpDocument document = null;
-        if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) {
+        if (identifier.mObjectHandle != CursorHelper.DUMMY_HANDLE_FOR_ROOT) {
+            MtpObjectInfo objectInfo;
             try {
-                document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle);
+                objectInfo = mMtpManager.getObjectInfo(
+                        identifier.mDeviceId, identifier.mObjectHandle);
             } catch (IOException e) {
                 throw new FileNotFoundException(e.getMessage());
             }
+            final MatrixCursor cursor = new MatrixCursor(projection);
+            CursorHelper.addToCursor(
+                    objectInfo,
+                    new Identifier(identifier.mDeviceId, identifier.mStorageId),
+                    cursor.newRow());
+            return cursor;
         } else {
             MtpRoot[] roots;
             try {
                 roots = mMtpManager.getRoots(identifier.mDeviceId);
-                if (roots != null) {
-                    for (final MtpRoot root : roots) {
-                        if (identifier.mStorageId == root.mStorageId) {
-                            document = new MtpDocument(root);
-                            break;
-                        }
-                    }
-                }
-                if (document == null) {
-                    throw new FileNotFoundException();
-                }
             } catch (IOException e) {
                 throw new FileNotFoundException(e.getMessage());
             }
+            for (final MtpRoot root : roots) {
+                if (identifier.mStorageId != root.mStorageId)
+                    continue;
+                final MatrixCursor cursor = new MatrixCursor(projection);
+                CursorHelper.addToCursor(root, cursor.newRow());
+                return cursor;
+            }
         }
 
-        final MatrixCursor cursor = new MatrixCursor(projection);
-        document.addToCursor(
-                new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow());
-        return cursor;
+        throw new FileNotFoundException();
     }
 
     @Override
@@ -167,13 +168,20 @@
     public ParcelFileDescriptor openDocument(
             String documentId, String mode, CancellationSignal signal)
                     throws FileNotFoundException {
-        if (!"r".equals(mode) && !"w".equals(mode)) {
-            // TODO: Support seekable file.
-            throw new UnsupportedOperationException("The provider does not support seekable file.");
-        }
         final Identifier identifier = Identifier.createFromDocumentId(documentId);
         try {
-            return mPipeManager.readDocument(mMtpManager, identifier);
+            switch (mode) {
+                case "r":
+                    return mPipeManager.readDocument(mMtpManager, identifier);
+                case "w":
+                    // TODO: Clear the parent document loader task (if exists) and call notify
+                    // when writing is completed.
+                    return mPipeManager.writeDocument(getContext(), mMtpManager, identifier);
+                default:
+                    // TODO: Add support for seekable files.
+                    throw new UnsupportedOperationException(
+                            "The provider does not support seekable file.");
+            }
         } catch (IOException error) {
             throw new FileNotFoundException(error.getMessage());
         }
@@ -202,8 +210,10 @@
             final int parentHandle =
                     mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle);
             mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
-            notifyChildDocumentsChange(new Identifier(
-                    identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId());
+            final Identifier parentIdentifier = new Identifier(
+                    identifier.mDeviceId, identifier.mStorageId, parentHandle);
+            mDocumentLoader.clearTask(parentIdentifier);
+            notifyChildDocumentsChange(parentIdentifier.toDocumentId());
         } catch (IOException error) {
             throw new FileNotFoundException(error.getMessage());
         }
@@ -211,7 +221,7 @@
 
     @Override
     public void onTrimMemory(int level) {
-        mDocumentLoader.clearCache();
+        mDocumentLoader.clearCompletedTasks();
     }
 
     @Override
@@ -219,11 +229,19 @@
             throws FileNotFoundException {
         try {
             final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+            final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
+            pipe[0].close();  // 0 bytes for a new document.
             final int objectHandle = mMtpManager.createDocument(
-                    parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
-                    displayName);
-            final String documentId =  new Identifier(parentId.mDeviceId, parentId.mStorageId,
+                    parentId.mDeviceId,
+                    new MtpObjectInfo.Builder()
+                            .setStorageId(parentId.mStorageId)
+                            .setParent(parentId.mObjectHandle)
+                            .setFormat(CursorHelper.mimeTypeToFormatType(mimeType))
+                            .setName(displayName)
+                            .build(), pipe[1]);
+            final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId,
                    objectHandle).toDocumentId();
+            mDocumentLoader.clearTask(parentId);
             notifyChildDocumentsChange(parentDocumentId);
             return documentId;
         } catch (IOException error) {
@@ -239,7 +257,7 @@
 
     void closeDevice(int deviceId) throws IOException {
         mMtpManager.closeDevice(deviceId);
-        mDocumentLoader.clearCache(deviceId);
+        mDocumentLoader.clearTasks(deviceId);
         mRootScanner.scanNow();
     }
 
@@ -248,7 +266,7 @@
         for (int deviceId : mMtpManager.getOpenedDeviceIds()) {
             try {
                 mMtpManager.closeDevice(deviceId);
-                mDocumentLoader.clearCache(deviceId);
+                mDocumentLoader.clearTasks(deviceId);
                 closed = true;
             } catch (IOException d) {
                 Log.d(TAG, "Failed to close the MTP device: " + deviceId);
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 27ba794..ca78a3e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -20,6 +20,7 @@
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
 import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
@@ -108,9 +109,10 @@
         return results;
     }
 
-    synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+    synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle)
+            throws IOException {
         final MtpDevice device = getDevice(deviceId);
-        return new MtpDocument(device.getObjectInfo(objectHandle));
+        return device.getObjectInfo(objectHandle);
     }
 
     synchronized int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle)
@@ -137,20 +139,20 @@
         }
     }
 
-    synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
-            String mimeType, String name) throws IOException {
+    synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo,
+            ParcelFileDescriptor source) throws IOException {
         final MtpDevice device = getDevice(deviceId);
-        final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
-                .setName(name)
-                .setStorageId(storageId)
-                .setParent(parentObjectHandle)
-                .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
-                .build();
-        final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
-        if (result == null) {
+        final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
+        if (sendObjectInfoResult == null) {
             throw new IOException("Failed to create a document");
         }
-        return result.getObjectHandle();
+        if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
+            if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
+                    sendObjectInfoResult.getCompressedSize(), source)) {
+                throw new IOException("Failed to send contents of a document");
+            }
+        }
+        return sendObjectInfoResult.getObjectHandle();
     }
 
     synchronized int getParent(int deviceId, int objectHandle) throws IOException {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index ba13b31..cd38f1e 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
@@ -16,10 +16,16 @@
 
 package com.android.mtp;
 
+import android.content.Context;
+import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
 import android.util.Log;
 
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.OutputStream;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -40,6 +46,13 @@
         return task.getReadingFileDescriptor();
     }
 
+    ParcelFileDescriptor writeDocument(Context context, MtpManager model, Identifier identifier)
+            throws IOException {
+        final Task task = new WriteDocumentTask(context, model, identifier);
+        mExecutor.execute(task);
+        return task.getWritingFileDescriptor();
+    }
+
     ParcelFileDescriptor readThumbnail(MtpManager model, Identifier identifier) throws IOException {
         final Task task = new GetThumbnailTask(model, identifier);
         mExecutor.execute(task);
@@ -60,6 +73,10 @@
         ParcelFileDescriptor getReadingFileDescriptor() {
             return mDescriptors[0];
         }
+
+        ParcelFileDescriptor getWritingFileDescriptor() {
+            return mDescriptors[1];
+        }
     }
 
     private static class ImportFileTask extends Task {
@@ -83,6 +100,65 @@
         }
     }
 
+    private static class WriteDocumentTask extends Task {
+        private final Context mContext;
+
+        WriteDocumentTask(Context context, MtpManager model, Identifier identifier)
+                throws IOException {
+            super(model, identifier);
+            mContext = context;
+        }
+
+        @Override
+        public void run() {
+            File tempFile = null;
+            try {
+                // Obtain a temporary file and copy the data to it.
+                tempFile = mContext.getCacheDir().createTempFile("mtp", "tmp");
+                try (
+                    final FileOutputStream tempOutputStream =
+                            new ParcelFileDescriptor.AutoCloseOutputStream(
+                                    ParcelFileDescriptor.open(
+                                            tempFile, ParcelFileDescriptor.MODE_WRITE_ONLY));
+                    final ParcelFileDescriptor.AutoCloseInputStream inputStream =
+                            new ParcelFileDescriptor.AutoCloseInputStream(mDescriptors[0])
+                ) {
+                    final byte[] buffer = new byte[32 * 1024];
+                    int bytes;
+                    while ((bytes = inputStream.read(buffer)) != -1) {
+                        mDescriptors[0].checkError();
+                        tempOutputStream.write(buffer, 0, bytes);
+                    }
+                    tempOutputStream.flush();
+                }
+
+                // Get the placeholder object info.
+                final MtpObjectInfo placeholderObjectInfo =
+                        mManager.getObjectInfo(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
+
+                // Delete the target object info if it already exists (as a placeholder).
+                mManager.deleteDocument(mIdentifier.mDeviceId, mIdentifier.mObjectHandle);
+
+                // Create the target object info with a correct file size and upload the file.
+                final MtpObjectInfo targetObjectInfo =
+                        new MtpObjectInfo.Builder(placeholderObjectInfo)
+                                .setCompressedSize((int) tempFile.length())
+                                .build();
+                final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
+                        tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
+                mManager.createDocument(mIdentifier.mDeviceId,
+                        targetObjectInfo, tempInputDescriptor);
+            } catch (IOException error) {
+                Log.w(MtpDocumentsProvider.TAG,
+                        "Failed to send a file because of: " + error.getMessage());
+            } finally {
+                if (tempFile != null) {
+                    tempFile.delete();
+                }
+            }
+        }
+    }
+
     private static class GetThumbnailTask extends Task {
         GetThumbnailTask(MtpManager model, Identifier identifier) throws IOException {
             super(model, identifier);
diff --git a/packages/MtpDocumentsProvider/tests/AndroidManifest.xml b/packages/MtpDocumentsProvider/tests/AndroidManifest.xml
index 50b7521..28ad3f4 100644
--- a/packages/MtpDocumentsProvider/tests/AndroidManifest.xml
+++ b/packages/MtpDocumentsProvider/tests/AndroidManifest.xml
@@ -5,10 +5,20 @@
 
     <application>
         <uses-library android:name="android.test.runner" />
+        <activity android:name="com.android.mtp.TestResultActivity"
+                  android:screenOrientation="locked"
+                  android:launchMode="singleInstance">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
     </application>
 
+    <instrumentation android:name="com.android.mtp.TestResultInstrumentation"
+        android:targetPackage="com.android.mtp"
+        android:label="Tests for MtpDocumentsProvider with the UI for output." />
     <instrumentation android:name="android.test.InstrumentationTestRunner"
         android:targetPackage="com.android.mtp"
-        android:label="Tests for MtpDocumentsProvider" />
-
+        android:label="Tests for MtpDocumentsProvider." />
 </manifest>
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
index 1e015bd..a012d7f 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 import android.database.Cursor;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
@@ -31,14 +32,14 @@
 
 @SmallTest
 public class DocumentLoaderTest extends AndroidTestCase {
-    private BlockableTestMtpMaanger mManager;
+    private BlockableTestMtpManager mManager;
     private TestContentResolver mResolver;
     private DocumentLoader mLoader;
     final private Identifier mParentIdentifier = new Identifier(0, 0, 0);
 
     @Override
     public void setUp() {
-        mManager = new BlockableTestMtpMaanger(getContext());
+        mManager = new BlockableTestMtpManager(getContext());
         mResolver = new TestContentResolver();
         mLoader = new DocumentLoader(mManager, mResolver);
     }
@@ -85,22 +86,17 @@
         for (int i = 0; i < childDocuments.length; i++) {
             final int objectHandle = i + 1;
             childDocuments[i] = objectHandle;
-            manager.setDocument(0, objectHandle, new MtpDocument(
-                    objectHandle,
-                    0 /* format */,
-                    "file" + objectHandle,
-                    new Date(),
-                    1024,
-                    0 /* thumbnail size */,
-                    false /* not read only */));
+            manager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                    .setObjectHandle(objectHandle)
+                    .build());
         }
         manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
     }
 
-    private static class BlockableTestMtpMaanger extends TestMtpManager {
+    private static class BlockableTestMtpManager extends TestMtpManager {
         final private Map<String, CountDownLatch> blockedDocuments = new HashMap<>();
 
-        BlockableTestMtpMaanger(Context context) {
+        BlockableTestMtpManager(Context context) {
             super(context);
         }
 
@@ -113,7 +109,7 @@
         }
 
         @Override
-        MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+        MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
             final CountDownLatch latch = blockedDocuments.get(pack(deviceId, objectHandle));
             if (latch != null) {
                 try {
@@ -122,7 +118,7 @@
                     fail();
                 }
             }
-            return super.getDocument(deviceId, objectHandle);
+            return super.getObjectInfo(deviceId, objectHandle);
         }
     }
 }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index 16be669..9b316be 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -17,9 +17,12 @@
 package com.android.mtp;
 
 import android.database.Cursor;
+import android.mtp.MtpConstants;
+import android.mtp.MtpObjectInfo.Builder;
+import android.mtp.MtpObjectInfo;
 import android.net.Uri;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -204,14 +207,14 @@
     }
 
     public void testQueryDocument() throws IOException {
-        mMtpManager.setDocument(0, 2, new MtpDocument(
-                2 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(1422716400000L) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                true /* read only */));
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
+                .setName("image.jpg")
+                .setDateModified(1422716400000L)
+                .setCompressedSize(1024 * 1024 * 5)
+                .setThumbCompressedSize(1024 * 50)
+                .build());
         final Cursor cursor = mProvider.queryDocument("0_1_2", null);
         assertEquals(1, cursor.getCount());
 
@@ -222,11 +225,35 @@
         assertEquals(1422716400000L, cursor.getLong(3));
         assertEquals(
                 DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
                 DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL,
                 cursor.getInt(4));
         assertEquals(1024 * 1024 * 5, cursor.getInt(5));
     }
 
+    public void testQueryDocument_directory() throws IOException {
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .setFormat(MtpConstants.FORMAT_ASSOCIATION)
+                .setName("directory")
+                .setDateModified(1422716400000L)
+                .build());
+        final Cursor cursor = mProvider.queryDocument("0_1_2", null);
+        assertEquals(1, cursor.getCount());
+
+        cursor.moveToNext();
+        assertEquals("0_1_2", cursor.getString(0));
+        assertEquals(DocumentsContract.Document.MIME_TYPE_DIR, cursor.getString(1));
+        assertEquals("directory", cursor.getString(2));
+        assertEquals(1422716400000L, cursor.getLong(3));
+        assertEquals(
+                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                DocumentsContract.Document.FLAG_SUPPORTS_WRITE |
+                DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE,
+                cursor.getInt(4));
+        assertEquals(0, cursor.getInt(5));
+    }
+
     public void testQueryDocument_forRoot() throws IOException {
         mMtpManager.setRoots(0, new MtpRoot[] {
                 new MtpRoot(
@@ -252,14 +279,14 @@
     public void testQueryChildDocuments() throws Exception {
         mMtpManager.setObjectHandles(0, 0, -1, new int[] { 1 });
 
-        mMtpManager.setDocument(0, 1, new MtpDocument(
-                1 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(0) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                true /* read only */));
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .setFormat(MtpConstants.FORMAT_EXIF_JPEG)
+                .setName("image.jpg")
+                .setCompressedSize(1024 * 1024 * 5)
+                .setThumbCompressedSize(5 * 1024)
+                .setProtectionStatus(MtpConstants.PROTECTION_STATUS_READ_ONLY)
+                .build());
 
         final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
         assertEquals(1, cursor.getCount());
@@ -269,10 +296,7 @@
         assertEquals("image/jpeg", cursor.getString(1));
         assertEquals("image.jpg", cursor.getString(2));
         assertEquals(0, cursor.getLong(3));
-        assertEquals(
-                DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
-                DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL,
-                cursor.getInt(4));
+        assertEquals(DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL, cursor.getInt(4));
         assertEquals(1024 * 1024 * 5, cursor.getInt(5));
 
         assertFalse(cursor.moveToNext());
@@ -298,15 +322,10 @@
     }
 
     public void testDeleteDocument() throws FileNotFoundException {
-        mMtpManager.setDocument(0, 1, new MtpDocument(
-                1 /* object handle */,
-                0x3801 /* JPEG */,
-                "image.jpg" /* display name */,
-                new Date(1422716400000L) /* modified date */,
-                1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */,
-                false /* not read only */));
-        mMtpManager.setParent(0, 1, 2);
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .setParent(2)
+                .build());
         mProvider.deleteDocument("0_0_1");
         assertEquals(1, mResolver.getChangeCount(
                 DocumentsContract.buildChildDocumentsUri(
@@ -314,7 +333,9 @@
     }
 
     public void testDeleteDocument_error() {
-        mMtpManager.setParent(0, 1, 2);
+        mMtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(2)
+                .build());
         try {
             mProvider.deleteDocument("0_0_1");
             fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
new file mode 100644
index 0000000..2c1f115
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import android.content.Context;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbManager;
+import android.test.InstrumentationTestCase;
+
+import java.util.HashMap;
+
+public class MtpManagerTest extends InstrumentationTestCase {
+    @RealDeviceTest
+    public void testBasic() throws Exception {
+        final UsbDevice usbDevice = findDevice();
+        final MtpManager manager = new MtpManager(getContext());
+        manager.openDevice(usbDevice.getDeviceId());
+        waitForStorages(manager, usbDevice.getDeviceId());
+        manager.closeDevice(usbDevice.getDeviceId());
+    }
+
+    private UsbDevice findDevice() throws InterruptedException {
+        final UsbManager usbManager = getContext().getSystemService(UsbManager.class);
+        while (true) {
+            final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
+            if (devices.size() == 0) {
+                show("Wait for devices.");
+                Thread.sleep(1000);
+                continue;
+            }
+            final UsbDevice device = devices.values().iterator().next();
+            final UsbDeviceConnection connection = usbManager.openDevice(device);
+            for (int i = 0; i < device.getInterfaceCount(); i++) {
+                // Since the test runs real environment, we need to call claim interface with
+                // force = true to rob interfaces from other applications.
+                connection.claimInterface(device.getInterface(i), true);
+                connection.releaseInterface(device.getInterface(i));
+            }
+            connection.close();
+            return device;
+        }
+    }
+
+    private void waitForStorages(MtpManager manager, int deviceId) throws Exception {
+        while (true) {
+            if (manager.getRoots(deviceId).length == 0) {
+                show("Wait for storages.");
+                Thread.sleep(1000);
+                continue;
+            }
+            return;
+        }
+    }
+
+    private void show(String message) {
+        if (!(getInstrumentation() instanceof TestResultInstrumentation)) {
+            return;
+        }
+        ((TestResultInstrumentation) getInstrumentation()).show(message);
+    }
+
+    private Context getContext() {
+        return getInstrumentation().getContext();
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
index 35918e1..53018cc 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -16,11 +16,13 @@
 
 package com.android.mtp;
 
+import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
 import java.io.IOException;
+import java.util.Date;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
@@ -30,45 +32,82 @@
     private static final byte[] HELLO_BYTES = new byte[] { 'h', 'e', 'l', 'l', 'o' };
 
     private TestMtpManager mtpManager;
-    private ExecutorService executor;
-    private PipeManager pipeManager;
+    private ExecutorService mExecutor;
+    private PipeManager mPipeManager;
 
     @Override
     public void setUp() {
         mtpManager = new TestMtpManager(getContext());
-        executor = Executors.newSingleThreadExecutor();
-        pipeManager = new PipeManager(executor);
+        mExecutor = Executors.newSingleThreadExecutor();
+        mPipeManager = new PipeManager(mExecutor);
     }
 
     public void testReadDocument_basic() throws Exception {
         mtpManager.setImportFileBytes(0, 1, HELLO_BYTES);
-        final ParcelFileDescriptor descriptor = pipeManager.readDocument(
+        final ParcelFileDescriptor descriptor = mPipeManager.readDocument(
                 mtpManager, new Identifier(0, 0, 1));
         assertDescriptor(descriptor, HELLO_BYTES);
     }
 
     public void testReadDocument_error() throws Exception {
         final ParcelFileDescriptor descriptor =
-                pipeManager.readDocument(mtpManager, new Identifier(0, 0, 1));
+                mPipeManager.readDocument(mtpManager, new Identifier(0, 0, 1));
         assertDescriptorError(descriptor);
     }
 
+    public void testWriteDocument_basic() throws Exception {
+        // Create a placeholder file which should be replaced by a real file later.
+        mtpManager.setObjectInfo(0, new MtpObjectInfo.Builder()
+                .setObjectHandle(1)
+                .build());
+
+        // Upload testing bytes.
+        final ParcelFileDescriptor descriptor = mPipeManager.writeDocument(
+                getContext(), mtpManager, new Identifier(0, 0, 1));
+        final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
+                new ParcelFileDescriptor.AutoCloseOutputStream(descriptor);
+        outputStream.write(HELLO_BYTES, 0, HELLO_BYTES.length);
+        outputStream.close();
+        mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+
+        // Check if the placeholder file is removed.
+        try {
+            final MtpObjectInfo placeholderDocument = mtpManager.getObjectInfo(0, 1);
+            fail();  // The placeholder file has not been deleted.
+        } catch (IOException e) {
+            // Expected error, as the file is gone.
+        }
+
+        // Confirm that the target file is created.
+        final MtpObjectInfo targetDocument = mtpManager.getObjectInfo(
+                0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
+        assertTrue(targetDocument != null);
+
+        // Verify uploaded bytes.
+        final byte[] uploadedBytes = mtpManager.getImportFileBytes(
+                0, TestMtpManager.CREATED_DOCUMENT_HANDLE);
+        assertEquals(HELLO_BYTES.length, uploadedBytes.length);
+        for (int i = 0; i < HELLO_BYTES.length; i++) {
+            assertEquals(HELLO_BYTES[i], uploadedBytes[i]);
+        }
+    }
+
     public void testReadThumbnail_basic() throws Exception {
         mtpManager.setThumbnail(0, 1, HELLO_BYTES);
-        final ParcelFileDescriptor descriptor = pipeManager.readThumbnail(
+        final ParcelFileDescriptor descriptor = mPipeManager.readThumbnail(
                 mtpManager, new Identifier(0, 0, 1));
         assertDescriptor(descriptor, HELLO_BYTES);
     }
 
     public void testReadThumbnail_error() throws Exception {
         final ParcelFileDescriptor descriptor =
-                pipeManager.readThumbnail(mtpManager, new Identifier(0, 0, 1));
+                mPipeManager.readThumbnail(mtpManager, new Identifier(0, 0, 1));
         assertDescriptorError(descriptor);
     }
 
     private void assertDescriptor(ParcelFileDescriptor descriptor, byte[] expectedBytes)
             throws IOException, InterruptedException {
-        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+        mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
         try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                 new ParcelFileDescriptor.AutoCloseInputStream(descriptor)) {
             byte[] results = new byte[100];
@@ -81,7 +120,7 @@
 
     private void assertDescriptorError(ParcelFileDescriptor descriptor)
             throws InterruptedException {
-        executor.awaitTermination(1000, TimeUnit.MILLISECONDS);
+        mExecutor.awaitTermination(1000, TimeUnit.MILLISECONDS);
         try {
             descriptor.checkError();
             fail();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
new file mode 100644
index 0000000..9641ad7
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mtp;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+
+@Target(ElementType.METHOD)
+@interface RealDeviceTest {}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
index 40de7b4..5605388 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java
@@ -17,10 +17,13 @@
 package com.android.mtp;
 
 import android.content.Context;
+import android.mtp.MtpObjectInfo;
+import android.mtp.MtpObjectInfo.Builder;
 import android.os.ParcelFileDescriptor;
 
 import java.io.IOException;
 import java.util.Arrays;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
@@ -28,6 +31,8 @@
 import java.util.TreeSet;
 
 public class TestMtpManager extends MtpManager {
+    public static final int CREATED_DOCUMENT_HANDLE = 1000;
+
     protected static String pack(int... args) {
         return Arrays.toString(args);
     }
@@ -35,10 +40,9 @@
     private final Set<Integer> mValidDevices = new HashSet<>();
     private final Set<Integer> mOpenedDevices = new TreeSet<>();
     private final Map<Integer, MtpRoot[]> mRoots = new HashMap<>();
-    private final Map<String, MtpDocument> mDocuments = new HashMap<>();
+    private final Map<String, MtpObjectInfo> mObjectInfos = new HashMap<>();
     private final Map<String, int[]> mObjectHandles = new HashMap<>();
     private final Map<String, byte[]> mThumbnailBytes = new HashMap<>();
-    private final Map<String, Integer> mParents = new HashMap<>();
     private final Map<String, byte[]> mImportFileBytes = new HashMap<>();
 
     TestMtpManager(Context context) {
@@ -49,28 +53,28 @@
         mValidDevices.add(deviceId);
     }
 
-    void setObjectHandles(int deviceId, int storageId, int objectHandle, int[] documents) {
-        mObjectHandles.put(pack(deviceId, storageId, objectHandle), documents);
+    void setObjectHandles(int deviceId, int storageId, int parentHandle, int[] objectHandles) {
+        mObjectHandles.put(pack(deviceId, storageId, parentHandle), objectHandles);
     }
 
     void setRoots(int deviceId, MtpRoot[] roots) {
         mRoots.put(deviceId, roots);
     }
 
-    void setDocument(int deviceId, int objectHandle, MtpDocument document) {
-        mDocuments.put(pack(deviceId, objectHandle), document);
+    void setObjectInfo(int deviceId, MtpObjectInfo objectInfo) {
+        mObjectInfos.put(pack(deviceId, objectInfo.getObjectHandle()), objectInfo);
     }
 
     void setImportFileBytes(int deviceId, int objectHandle, byte[] bytes) {
         mImportFileBytes.put(pack(deviceId, objectHandle), bytes);
     }
 
-    void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
-        mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
+    byte[] getImportFileBytes(int deviceId, int objectHandle) {
+        return mImportFileBytes.get(pack(deviceId, objectHandle));
     }
 
-    void setParent(int deviceId, int objectHandle, int parentObjectHandle) {
-        mParents.put(pack(deviceId, objectHandle), parentObjectHandle);
+    void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
+        mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
     }
 
     @Override
@@ -99,12 +103,12 @@
     }
 
     @Override
-    MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
+    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
-        if (mDocuments.containsKey(key)) {
-            return mDocuments.get(key);
+        if (mObjectInfos.containsKey(key)) {
+            return mObjectInfos.get(key);
         } else {
-            throw new IOException("getDocument error: " + key);
+            throw new IOException("getObjectInfo error: " + key);
         }
     }
 
@@ -119,8 +123,9 @@
     }
 
     @Override
-    void importFile(int deviceId, int storageId, ParcelFileDescriptor target) throws IOException {
-        final String key = pack(deviceId, storageId);
+    void importFile(int deviceId, int objectHandle, ParcelFileDescriptor target)
+            throws IOException {
+        final String key = pack(deviceId, objectHandle);
         if (mImportFileBytes.containsKey(key)) {
             try (final ParcelFileDescriptor.AutoCloseOutputStream outputStream =
                     new ParcelFileDescriptor.AutoCloseOutputStream(target)) {
@@ -132,6 +137,29 @@
     }
 
     @Override
+    int createDocument(int deviceId, MtpObjectInfo objectInfo, ParcelFileDescriptor source)
+            throws IOException {
+        final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
+        if (mObjectInfos.containsKey(key)) {
+            throw new IOException();
+        }
+        mObjectInfos.put(key, objectInfo);
+        if (objectInfo.getFormat() != 0x3001) {
+            try (final ParcelFileDescriptor.AutoCloseInputStream inputStream =
+                    new ParcelFileDescriptor.AutoCloseInputStream(source)) {
+                final byte[] buffer = new byte[objectInfo.getCompressedSize()];
+                if (inputStream.read(buffer, 0, objectInfo.getCompressedSize()) !=
+                        objectInfo.getCompressedSize()) {
+                    throw new IOException();
+                }
+
+                mImportFileBytes.put(pack(deviceId, CREATED_DOCUMENT_HANDLE), buffer);
+            }
+        }
+        return CREATED_DOCUMENT_HANDLE;
+    }
+
+    @Override
     byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
         if (mThumbnailBytes.containsKey(key)) {
@@ -144,18 +172,18 @@
     @Override
     void deleteDocument(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
-        if (mDocuments.containsKey(key)) {
-            mDocuments.remove(key);
+        if (mObjectInfos.containsKey(key)) {
+            mObjectInfos.remove(key);
         } else {
             throw new IOException();
         }
     }
 
     @Override
-    synchronized int getParent(int deviceId, int objectHandle) throws IOException {
+    int getParent(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
-        if (mParents.containsKey(key)) {
-            return mParents.get(key);
+        if (mObjectInfos.containsKey(key)) {
+            return mObjectInfos.get(key).getParent();
         } else {
             throw new IOException();
         }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.java
new file mode 100644
index 0000000..9f2bb2a
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultActivity.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 com.android.mtp;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+
+/**
+ * Activity that shows the test results instead of adb while using USB port to connect MTP device.
+ */
+public class TestResultActivity extends Activity {
+    private final static String TAG = "MtpDocumentsProviderTest";
+    private TextView mTextView;
+
+    static void show(Context context, String message) {
+        Log.d(TAG, message);
+        final Intent intent = new Intent(context, TestResultActivity.class);
+        intent.putExtra("message", message);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+    }
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        final LinearLayout linearLayout = new LinearLayout(this);
+        linearLayout.setOrientation(LinearLayout.VERTICAL);
+        setContentView(linearLayout);
+
+        mTextView = new TextView(this);
+        mTextView.setText(getIntent().getStringExtra("message") + "\n");
+        linearLayout.addView(
+                mTextView, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+    }
+
+    @Override
+    protected void onNewIntent(Intent intent) {
+        super.onNewIntent(intent);
+        mTextView.setText(mTextView.getText() + intent.getStringExtra("message") + "\n");
+    }
+}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
new file mode 100644
index 0000000..9824d28
--- /dev/null
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
@@ -0,0 +1,52 @@
+package com.android.mtp;
+
+import android.os.Bundle;
+import android.test.InstrumentationTestRunner;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestListener;
+
+public class TestResultInstrumentation extends InstrumentationTestRunner implements TestListener {
+    private boolean mHasError = false;
+
+    @Override
+    public void onCreate(Bundle arguments) {
+        super.onCreate(arguments);
+        addTestListener(this);
+    }
+
+    @Override
+    public void addError(Test test, Throwable t) {
+        mHasError = true;
+        show("ERROR", test, t);
+    }
+
+    @Override
+    public void addFailure(Test test, AssertionFailedError t) {
+        mHasError = true;
+        show("FAIL", test, t);
+    }
+
+    @Override
+    public void endTest(Test test) {
+        if (!mHasError) {
+            show("PASS", test, null);
+        }
+    }
+
+    @Override
+    public void startTest(Test test) {
+        mHasError = false;
+    }
+
+    void show(String message) {
+        TestResultActivity.show(getContext(), "    " + message);
+    }
+
+    private void show(String tag, Test test, Throwable t) {
+        TestResultActivity.show(
+                getContext(),
+                String.format("[%s] %s %s", tag, test.toString(), t != null ? t.getMessage() : ""));
+    }
+}
diff --git a/packages/PrintSpooler/res/values-ja/strings.xml b/packages/PrintSpooler/res/values-ja/strings.xml
index 6029425..8ef7517 100644
--- a/packages/PrintSpooler/res/values-ja/strings.xml
+++ b/packages/PrintSpooler/res/values-ja/strings.xml
@@ -53,7 +53,7 @@
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"検索ボックスは表示されていません"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"プリンタを追加"</string>
     <string name="print_select_printer" msgid="7388760939873368698">"プリンタを選択"</string>
-    <string name="print_forget_printer" msgid="5035287497291910766">"プリンタを切断"</string>
+    <string name="print_forget_printer" msgid="5035287497291910766">"プリンタを削除"</string>
     <plurals name="print_search_result_count_utterance" formatted="false" msgid="6997663738361080868">
       <item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g>台のプリンタが見つかりました</item>
       <item quantity="one"><xliff:g id="COUNT_0">%1$s</xliff:g>台のプリンタが見つかりました</item>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index b0429ef..e4b1ed8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -539,10 +539,10 @@
          * Otherwise, allow the connect on UUID change.
          */
         if (!mProfiles.isEmpty()
-                && ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime()
-                || (mConnectAttempted == 0))) {
+                && ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime())) {
             connectWithoutResettingTimer(false);
         }
+
         dispatchAttributesChanged();
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 5a14967..ee296d9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -109,7 +109,7 @@
 
     static String dbNameForUser(final int userHandle) {
         // The owner gets the unadorned db name;
-        if (userHandle == UserHandle.USER_OWNER) {
+        if (userHandle == UserHandle.USER_SYSTEM) {
             return DATABASE_NAME;
         } else {
             // Place the database in the user-specific data tree so that it's
@@ -186,8 +186,8 @@
 
         createSecureTable(db);
 
-        // Only create the global table for the singleton 'owner' user
-        if (mUserHandle == UserHandle.USER_OWNER) {
+        // Only create the global table for the singleton 'owner/system' user
+        if (mUserHandle == UserHandle.USER_SYSTEM) {
             createGlobalTable(db);
         }
 
@@ -1252,7 +1252,7 @@
 
         if (upgradeVersion == 82) {
             // Move to per-user settings dbs
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
 
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
@@ -1306,7 +1306,7 @@
         }
 
         if (upgradeVersion == 84) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1331,7 +1331,7 @@
         }
 
         if (upgradeVersion == 85) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     // Fix up the migration, ignoring already-migrated elements, to snap up to
@@ -1348,7 +1348,7 @@
         }
 
         if (upgradeVersion == 86) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] settingsToMove = {
@@ -1367,7 +1367,7 @@
         }
 
         if (upgradeVersion == 87) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] settingsToMove = {
@@ -1386,7 +1386,7 @@
         }
 
         if (upgradeVersion == 88) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] settingsToMove = {
@@ -1432,7 +1432,7 @@
         }
 
         if (upgradeVersion == 89) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] prefixesToMove = {
@@ -1452,7 +1452,7 @@
         }
 
         if (upgradeVersion == 90) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] systemToGlobal = {
@@ -1485,7 +1485,7 @@
         }
 
         if (upgradeVersion == 91) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     // Move ringer mode from system to global settings
@@ -1505,7 +1505,7 @@
             try {
                 stmt = db.compileStatement("INSERT OR IGNORE INTO secure(name,value)"
                         + " VALUES(?,?);");
-                if (mUserHandle == UserHandle.USER_OWNER) {
+                if (mUserHandle == UserHandle.USER_SYSTEM) {
                     // consider existing primary users to have made it through user setup
                     // if the globally-scoped device-provisioned bit is set
                     // (indicating they already made it through setup as primary)
@@ -1526,7 +1526,7 @@
 
         if (upgradeVersion == 93) {
             // Redo this step, since somehow it didn't work the first time for some users
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     // Migrate now-global settings
@@ -1547,7 +1547,7 @@
 
         if (upgradeVersion == 94) {
             // Add wireless charging started sound setting
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1565,7 +1565,7 @@
         }
 
         if (upgradeVersion == 95) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 try {
                     String[] settingsToMove = { Settings.Global.BUGREPORT_IN_POWER_MENU };
@@ -1584,7 +1584,7 @@
         }
 
         if (upgradeVersion == 97) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1613,7 +1613,7 @@
 
         if (upgradeVersion == 100) {
             // note: LOCK_SCREEN_SHOW_NOTIFICATIONS now handled in version 106
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1631,7 +1631,7 @@
         }
 
         if (upgradeVersion == 101) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1653,7 +1653,7 @@
             try {
                 // The INSTALL_NON_MARKET_APPS setting is becoming per-user rather
                 // than device-global.
-                if (mUserHandle == UserHandle.USER_OWNER) {
+                if (mUserHandle == UserHandle.USER_SYSTEM) {
                     // In the owner user, the global table exists so we can migrate the
                     // entry from there to the secure table, preserving its value.
                     String[] globalToSecure = {
@@ -1693,7 +1693,7 @@
         }
 
         if (upgradeVersion < 105) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1719,7 +1719,7 @@
                         + " VALUES(?,?);");
                 loadIntegerSetting(stmt, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
                         R.integer.def_lock_screen_show_notifications);
-                if (mUserHandle == UserHandle.USER_OWNER) {
+                if (mUserHandle == UserHandle.USER_SYSTEM) {
                     final int oldShow = getIntValueFromTable(db,
                             TABLE_GLOBAL, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, -1);
                     if (oldShow >= 0) {
@@ -1741,7 +1741,7 @@
 
         if (upgradeVersion < 107) {
             // Add trusted sound setting
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1816,7 +1816,7 @@
 
         if (upgradeVersion < 111) {
             // reset ringer mode, so it doesn't force zen mode to follow
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1833,7 +1833,7 @@
         }
 
         if (upgradeVersion < 112) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 // When device name was added, we went with Manufacturer + Model, device name should
                 // actually be Model only.
                 // Update device name to Model if it wasn't modified by user.
@@ -1874,7 +1874,7 @@
         // We skipped 114 to handle a merge conflict with the introduction of theater mode.
 
         if (upgradeVersion < 115) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -1892,7 +1892,7 @@
         }
 
         if (upgradeVersion < 116) {
-            if (mUserHandle == UserHandle.USER_OWNER) {
+            if (mUserHandle == UserHandle.USER_SYSTEM) {
                 db.beginTransaction();
                 SQLiteStatement stmt = null;
                 try {
@@ -2066,7 +2066,7 @@
                     LockPatternUtils lpu = new LockPatternUtils(mContext);
                     List<LockPatternView.Cell> cellPattern =
                             LockPatternUtils.stringToPattern(lockPattern);
-                    lpu.saveLockPattern(cellPattern, null, UserHandle.USER_OWNER);
+                    lpu.saveLockPattern(cellPattern, null, UserHandle.USER_SYSTEM);
                 } catch (IllegalArgumentException e) {
                     // Don't want corrupted lock pattern to hang the reboot process
                 }
@@ -2343,8 +2343,8 @@
     private void loadSettings(SQLiteDatabase db) {
         loadSystemSettings(db);
         loadSecureSettings(db);
-        // The global table only exists for the 'owner' user
-        if (mUserHandle == UserHandle.USER_OWNER) {
+        // The global table only exists for the 'owner/system' user
+        if (mUserHandle == UserHandle.USER_SYSTEM) {
             loadGlobalSettings(db);
         }
     }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index 952b220..1d71346 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -123,7 +123,8 @@
         }
 
         if (sBroadcastOnRestore.contains(name)) {
-            oldValue = table.lookup(cr, name, UserHandle.USER_OWNER);
+            // TODO: http://b/22388012
+            oldValue = table.lookup(cr, name, UserHandle.USER_SYSTEM);
             sendBroadcast = true;
         }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 73971ad..8b1caf9 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -18,7 +18,7 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
-import android.app.AppOpsManager;
+import android.app.AppGlobals;
 import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentProvider;
@@ -27,6 +27,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
@@ -47,6 +48,7 @@
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -208,13 +210,13 @@
     private volatile UserManager mUserManager;
 
     // We have to call in the package manager with no lock held,
-    private volatile PackageManager mPackageManager;
+    private volatile IPackageManager mPackageManager;
 
     @Override
     public boolean onCreate() {
         synchronized (mLock) {
-            mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
-            mPackageManager = getContext().getPackageManager();
+            mUserManager = UserManager.get(getContext());
+            mPackageManager = AppGlobals.getPackageManager();
             mSettingsRegistry = new SettingsRegistry();
         }
         registerBroadcastReceivers();
@@ -496,7 +498,7 @@
     }
 
     private void dumpForUser(int userId, PrintWriter pw) {
-        if (userId == UserHandle.USER_OWNER) {
+        if (userId == UserHandle.USER_SYSTEM) {
             pw.println("GLOBAL SETTINGS (user " + userId + ")");
             Cursor globalCursor = getAllGlobalSettings(ALL_COLUMNS);
             dumpSettings(globalCursor, pw);
@@ -547,7 +549,7 @@
             @Override
             public void onReceive(Context context, Intent intent) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                        UserHandle.USER_OWNER);
+                        UserHandle.USER_SYSTEM);
 
                 switch (intent.getAction()) {
                     case Intent.ACTION_USER_REMOVED: {
@@ -584,7 +586,7 @@
         synchronized (mLock) {
             // Get the settings.
             SettingsState settingsState = mSettingsRegistry.getSettingsLocked(
-                    SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                    SettingsRegistry.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
 
             List<String> names = settingsState.getSettingNamesLocked();
 
@@ -612,7 +614,7 @@
         // Get the value.
         synchronized (mLock) {
             return mSettingsRegistry.getSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                    UserHandle.USER_OWNER, name);
+                    UserHandle.USER_SYSTEM, name);
         }
     }
 
@@ -656,19 +658,19 @@
                 case MUTATION_OPERATION_INSERT: {
                     return mSettingsRegistry
                             .insertSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                                    UserHandle.USER_OWNER, name, value, getCallingPackage());
+                                    UserHandle.USER_SYSTEM, name, value, getCallingPackage());
                 }
 
                 case MUTATION_OPERATION_DELETE: {
                     return mSettingsRegistry.deleteSettingLocked(
                             SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                            UserHandle.USER_OWNER, name);
+                            UserHandle.USER_SYSTEM, name);
                 }
 
                 case MUTATION_OPERATION_UPDATE: {
                     return mSettingsRegistry
                             .updateSettingLocked(SettingsRegistry.SETTINGS_TYPE_GLOBAL,
-                                    UserHandle.USER_OWNER, name, value, getCallingPackage());
+                                    UserHandle.USER_SYSTEM, name, value, getCallingPackage());
                 }
             }
         }
@@ -903,7 +905,7 @@
         }
 
         // Enforce what the calling package can mutate the system settings.
-        enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name);
+        enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name, runAsUserId);
 
         // Resolve the userId on whose behalf the call is made.
         final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
@@ -1001,7 +1003,7 @@
     }
 
     private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
-            String name) {
+            String name, int userId) {
         // System/root/shell can mutate whatever secure settings they want.
         final int callingUid = Binder.getCallingUid();
         if (callingUid == android.os.Process.SYSTEM_UID
@@ -1019,7 +1021,7 @@
                 }
 
                 // The calling package is already verified.
-                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
 
                 // Privileged apps can do whatever they want.
                 if ((packageInfo.applicationInfo.privateFlags
@@ -1039,7 +1041,7 @@
                 }
 
                 // The calling package is already verified.
-                PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+                PackageInfo packageInfo = getCallingPackageInfoOrThrow(userId);
 
                 // Privileged apps can do whatever they want.
                 if ((packageInfo.applicationInfo.privateFlags &
@@ -1053,17 +1055,17 @@
         }
     }
 
-    private PackageInfo getCallingPackageInfoOrThrow() {
+    private PackageInfo getCallingPackageInfoOrThrow(int userId) {
         try {
-            return mPackageManager.getPackageInfo(getCallingPackage(), 0);
-        } catch (PackageManager.NameNotFoundException e) {
+            return mPackageManager.getPackageInfo(getCallingPackage(), 0, userId);
+        } catch (RemoteException e) {
             throw new IllegalStateException("Calling package doesn't exist");
         }
     }
 
     private int getGroupParentLocked(int userId) {
         // Most frequent use case.
-        if (userId == UserHandle.USER_OWNER) {
+        if (userId == UserHandle.USER_SYSTEM) {
             return userId;
         }
         // We are in the same process with the user manager and the returned
@@ -1401,8 +1403,8 @@
             migrateLegacySettingsForUserIfNeededLocked(userId);
 
             // Ensure global settings loaded if owner.
-            if (userId == UserHandle.USER_OWNER) {
-                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+            if (userId == UserHandle.USER_SYSTEM) {
+                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
                 ensureSettingsStateLocked(globalKey);
             }
 
@@ -1541,7 +1543,7 @@
 
         private void migrateAllLegacySettingsIfNeeded() {
             synchronized (mLock) {
-                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                final int key = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
                 File globalFile = getSettingsFile(key);
                 if (globalFile.exists()) {
                     return;
@@ -1591,7 +1593,7 @@
         private void migrateLegacySettingsForUserLocked(DatabaseHelper dbHelper,
                 SQLiteDatabase database, int userId) {
             // Move over the global settings if owner.
-            if (userId == UserHandle.USER_OWNER) {
+            if (userId == UserHandle.USER_SYSTEM) {
                 final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, userId);
                 ensureSettingsStateLocked(globalKey);
                 SettingsState globalSettings = mSettingsStates.get(globalKey);
@@ -1898,7 +1900,7 @@
                 }
 
                 // Set the global settings version if owner.
-                if (mUserId == UserHandle.USER_OWNER) {
+                if (mUserId == UserHandle.USER_SYSTEM) {
                     SettingsState globalSettings = getSettingsLocked(
                             SettingsRegistry.SETTINGS_TYPE_GLOBAL, mUserId);
                     globalSettings.setVersionLocked(newVersion);
@@ -1914,7 +1916,7 @@
             }
 
             private SettingsState getGlobalSettingsLocked() {
-                return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_OWNER);
+                return getSettingsLocked(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
             }
 
             private SettingsState getSecureSettingsLocked(int userId) {
@@ -1960,7 +1962,7 @@
 
                 // v119: Reset zen + ringer mode.
                 if (currentVersion == 118) {
-                    if (userId == UserHandle.USER_OWNER) {
+                    if (userId == UserHandle.USER_SYSTEM) {
                         final SettingsState globalSettings = getGlobalSettingsLocked();
                         globalSettings.updateSettingLocked(Settings.Global.ZEN_MODE,
                                 Integer.toString(Settings.Global.ZEN_MODE_OFF),
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
index c7cc89b..8e56f47 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/BaseSettingsProviderTest.java
@@ -48,7 +48,7 @@
             Settings.NameValueTable.NAME, Settings.NameValueTable.VALUE
     };
 
-    protected int mSecondaryUserId = UserHandle.USER_OWNER;
+    protected int mSecondaryUserId = UserHandle.USER_SYSTEM;
 
     @Override
     public void setContext(Context context) {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
index d581f3b..a09d5fe 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderPerformanceTest.java
@@ -47,7 +47,7 @@
 
                 // Make sure the setting changed.
                 String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
-                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                        FAKE_SETTING_NAME, UserHandle.USER_SYSTEM);
                 assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
 
                 // Set the setting to its second value.
@@ -56,7 +56,7 @@
 
                 // Make sure the setting changed.
                 String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
-                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                        FAKE_SETTING_NAME, UserHandle.USER_SYSTEM);
                 assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
             }
         } finally {
@@ -86,20 +86,20 @@
             for (int i = 0; i < ITERATION_COUNT; i++) {
                 // Set the setting to its first value.
                 setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
-                        FAKE_SETTING_VALUE, UserHandle.USER_OWNER);
+                        FAKE_SETTING_VALUE, UserHandle.USER_SYSTEM);
 
                 // Make sure the setting changed.
                 String firstValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
-                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                        FAKE_SETTING_NAME, UserHandle.USER_SYSTEM);
                 assertEquals("Setting value didn't change", FAKE_SETTING_VALUE, firstValue);
 
                 // Set the setting to its second value.
                 setStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL, FAKE_SETTING_NAME,
-                        FAKE_SETTING_VALUE_1, UserHandle.USER_OWNER);
+                        FAKE_SETTING_VALUE_1, UserHandle.USER_SYSTEM);
 
                 // Make sure the setting changed.
                 String secondValue = getStringViaFrontEndApiSetting(SETTING_TYPE_GLOBAL,
-                        FAKE_SETTING_NAME, UserHandle.USER_OWNER);
+                        FAKE_SETTING_NAME, UserHandle.USER_SYSTEM);
                 assertEquals("Setting value didn't change", FAKE_SETTING_VALUE_1, secondValue);
             }
         } finally {
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
index ad56b9d..8ca1b46 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsProviderTest.java
@@ -46,40 +46,40 @@
 
     private final Object mLock = new Object();
 
-    public void testSetAndGetGlobalViaFrontEndApiForOwnerUser() throws Exception {
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_OWNER);
+    public void testSetAndGetGlobalViaFrontEndApiForSystemUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
     }
 
-    public void testSetAndGetGlobalViaFrontEndApiForNonOwnerUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+    public void testSetAndGetGlobalViaFrontEndApiForNonSystemUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
-                    + "testSetAndGetGlobalViaFrontEndApiForNonOwnerUser");
+                    + "testSetAndGetGlobalViaFrontEndApiForNonSystemUser");
             return;
         }
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_GLOBAL, mSecondaryUserId);
     }
 
-    public void testSetAndGetSecureViaFrontEndApiForOwnerUser() throws Exception {
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_OWNER);
+    public void testSetAndGetSecureViaFrontEndApiForSystemUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, UserHandle.USER_SYSTEM);
     }
 
-    public void testSetAndGetSecureViaFrontEndApiForNonOwnerUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+    public void testSetAndGetSecureViaFrontEndApiForNonSystemUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
-                    + "testSetAndGetSecureViaFrontEndApiForNonOwnerUser");
+                    + "testSetAndGetSecureViaFrontEndApiForNonSystemUser");
             return;
         }
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SECURE, mSecondaryUserId);
     }
 
-    public void testSetAndGetSystemViaFrontEndApiForOwnerUser() throws Exception {
-        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_OWNER);
+    public void testSetAndGetSystemViaFrontEndApiForSystemUser() throws Exception {
+        performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, UserHandle.USER_SYSTEM);
     }
 
-    public void testSetAndGetSystemViaFrontEndApiForNonOwnerUser() throws Exception {
-        if (mSecondaryUserId == UserHandle.USER_OWNER) {
+    public void testSetAndGetSystemViaFrontEndApiForNonSystemUser() throws Exception {
+        if (mSecondaryUserId == UserHandle.USER_SYSTEM) {
             Log.w(LOG_TAG, "No secondary user. Skipping "
-                    + "testSetAndGetSystemViaFrontEndApiForNonOwnerUser");
+                    + "testSetAndGetSystemViaFrontEndApiForNonSystemUser");
             return;
         }
         performSetAndGetSettingTestViaFrontEndApi(SETTING_TYPE_SYSTEM, mSecondaryUserId);
@@ -357,7 +357,7 @@
             public void run() {
                 insertStringViaProviderApi(type, name, value, withTableRowUri);
             }
-        }, type, name, value, UserHandle.USER_OWNER);
+        }, type, name, value, UserHandle.USER_SYSTEM);
     }
 
     private void setSettingAndAssertSuccessfulChange(Runnable setCommand, final int type,
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index efacd2c..05591cc 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -39,6 +39,7 @@
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <!-- System tool permissions granted to the shell. -->
     <uses-permission android:name="android.permission.REAL_GET_TASKS" />
     <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
@@ -65,6 +66,7 @@
     <uses-permission android:name="android.permission.READ_INPUT_STATE" />
     <uses-permission android:name="android.permission.SET_ORIENTATION" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.MOVE_PACKAGE" />
     <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
     <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
     <uses-permission android:name="android.permission.DELETE_PACKAGES" />
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_1_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_1_animation.xml
new file mode 100755
index 0000000..1c50165
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_1_animation.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="strokeColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="strokeAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="383"
+        android:propertyName="trimPathStart"
+        android:valueFrom="0.5001"
+        android:valueTo="0.0"
+        android:valueType="floatType"
+        android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_3" />
+    <objectAnimator
+        android:duration="383"
+        android:propertyName="trimPathEnd"
+        android:valueFrom="1.5"
+        android:valueTo="0.0"
+        android:valueType="floatType"
+        android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_1" />
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_2_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_2_animation.xml
new file mode 100755
index 0000000..598255c
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_ellipse_path_2_animation.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueTo="M 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="233"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+            android:valueTo="M 0.0,-1.988645 c 1.09829830627,0.0 1.988645,0.890346693734 1.988645,1.988645 c 0.0,1.09829830627 -0.890346693734,1.988645 -1.988645,1.988645 c -1.09829830627,0.0 -1.988645,-0.890346693734 -1.988645,-1.988645 c 0.0,-1.09829830627 0.890346693734,-1.988645 1.988645,-1.988645 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_1" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_exclamation_dot_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_exclamation_dot_animation.xml
new file mode 100755
index 0000000..7e0fa43
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_exclamation_dot_animation.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="133"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M -0.00391,5.333 c 0.00065,-0.22217 0.00326,-1.11083 0.00391,-1.333"
+        android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_0" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="83"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="83"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_lock_left_side_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_lock_left_side_animation.xml
new file mode 100755
index 0000000..f413cbf
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_lock_left_side_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="scaleX"
+            android:valueFrom="1.33333"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="scaleX"
+            android:valueFrom="1.33333"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="scaleY"
+            android:valueFrom="1.33333"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="scaleY"
+            android:valueFrom="1.33333"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_lock_right_side_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_lock_right_side_animation.xml
new file mode 100755
index 0000000..f413cbf
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_lock_right_side_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="scaleX"
+            android:valueFrom="1.33333"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="scaleX"
+            android:valueFrom="1.33333"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="scaleY"
+            android:valueFrom="1.33333"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="scaleY"
+            android:valueFrom="1.33333"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_lock_top_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_lock_top_animation.xml
new file mode 100755
index 0000000..2518041
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_lock_top_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="333"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_path_1_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_path_1_animation.xml
new file mode 100755
index 0000000..15f8d2e
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_path_1_animation.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.02685546875,-4.96875 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 -0.00936889648438,3.9296875 -0.00936889648438,3.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0028076171875,0.0234375 -0.0028076171875,0.0234375 c 0.0,0.0 0.010498046875,-0.015625 0.010498046875,-0.015625 c 0.0,0.0 0.985595703125,0.0078125 0.985595703125,0.0078125 c 0.0,0.0 0.017578125,-6.015625 0.017578125,-6.015625 c 0.0,0.0 0.104400634766,0.0546875 -0.99560546875,0.0546875 Z"
+            android:valueTo="M 0.02685546875,-4.96875 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 -0.00936889648438,3.9296875 -0.00936889648438,3.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0028076171875,0.0234375 -0.0028076171875,0.0234375 c 0.0,0.0 0.010498046875,-0.015625 0.010498046875,-0.015625 c 0.0,0.0 0.985595703125,0.0078125 0.985595703125,0.0078125 c 0.0,0.0 0.017578125,-6.015625 0.017578125,-6.015625 c 0.0,0.0 0.104400634766,0.0546875 -0.99560546875,0.0546875 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.02685546875,-4.96875 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 -0.00936889648438,3.9296875 -0.00936889648438,3.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0028076171875,0.0234375 -0.0028076171875,0.0234375 c 0.0,0.0 0.010498046875,-0.015625 0.010498046875,-0.015625 c 0.0,0.0 0.985595703125,0.0078125 0.985595703125,0.0078125 c 0.0,0.0 0.017578125,-6.015625 0.017578125,-6.015625 c 0.0,0.0 0.104400634766,0.0546875 -0.99560546875,0.0546875 Z"
+            android:valueTo="M 1.63623046875,-4.953125 c 0.0,0.0 -1.61499023438,0.0 -1.61499023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 0.0118713378906,7.9296875 0.0118713378906,7.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 1.61987304688,0.0 1.61987304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 -0.01123046875,-7.9296875 -0.01123046875,-7.9296875 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="pathData"
+            android:valueFrom="M 1.63623046875,-4.953125 c 0.0,0.0 -1.61499023438,0.0 -1.61499023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 0.0118713378906,7.9296875 0.0118713378906,7.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 1.61987304688,0.0 1.61987304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 -0.01123046875,-7.9296875 -0.01123046875,-7.9296875 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueTo="M 6.00561523438,-4.046875 c 0.0,0.0 -5.98999023438,0.0 -5.98999023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 5.98812866211,0.0 5.98812866211,0.0 c 0.0,0.0 0.00064086914062,10.0 0.00064086914062,10.0 c 0.0,0.0 -5.98840332031,0.0 -5.98840332031,0.0 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 5.99487304688,0.0 5.99487304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.0 0.0,-10.0 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_4" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_path_2_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_path_2_animation.xml
new file mode 100755
index 0000000..aa81fcf
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_path_2_animation.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0252990722656,-2.96914672852 c 0.0,0.0 -0.00390625,0.0160217285156 -0.00390625,0.0160217285156 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 0.005615234375,-0.015625 0.005615234375,-0.015625 c -1.10000610352,0.0 -1.01220703125,-0.0546875 -1.01220703125,-0.0546875 c 0.0,0.0 -0.017578125,6.015625 -0.017578125,6.015625 c 0.0,0.0 -0.0777893066406,-0.0078125 1.02221679688,-0.0078125 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 -0.002685546875,-0.0244140625 -0.002685546875,-0.0244140625 c 0.0,0.0 0.00390625,-0.0152587890625 0.00390625,-0.0152587890625 c 0.0,0.0 0.0104064941406,-3.92947387695 0.0104064941406,-3.92947387695 Z"
+            android:valueTo="M 0.0252990722656,-2.96914672852 c 0.0,0.0 -0.00390625,0.0160217285156 -0.00390625,0.0160217285156 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 0.005615234375,-0.015625 0.005615234375,-0.015625 c -1.10000610352,0.0 -1.01220703125,-0.0546875 -1.01220703125,-0.0546875 c 0.0,0.0 -0.017578125,6.015625 -0.017578125,6.015625 c 0.0,0.0 -0.0777893066406,-0.0078125 1.02221679688,-0.0078125 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 -0.002685546875,-0.0244140625 -0.002685546875,-0.0244140625 c 0.0,0.0 0.00390625,-0.0152587890625 0.00390625,-0.0152587890625 c 0.0,0.0 0.0104064941406,-3.92947387695 0.0104064941406,-3.92947387695 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="183"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0252990722656,-2.96914672852 c 0.0,0.0 -0.00390625,0.0160217285156 -0.00390625,0.0160217285156 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 0.005615234375,-0.015625 0.005615234375,-0.015625 c -1.10000610352,0.0 -1.01220703125,-0.0546875 -1.01220703125,-0.0546875 c 0.0,0.0 -0.017578125,6.015625 -0.017578125,6.015625 c 0.0,0.0 -0.0777893066406,-0.0078125 1.02221679688,-0.0078125 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 -0.002685546875,-0.0244140625 -0.002685546875,-0.0244140625 c 0.0,0.0 0.00390625,-0.0152587890625 0.00390625,-0.0152587890625 c 0.0,0.0 0.0104064941406,-3.92947387695 0.0104064941406,-3.92947387695 Z"
+            android:valueTo="M 0.0252990722656,-2.96975708008 c 0.0,0.0 -0.00390625,0.0166320800781 -0.00390625,0.0166320800781 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -1.63500976562,0.0 -1.63500976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.01123046875,7.9296875 0.01123046875,7.9296875 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 1.63500976562,0.0 1.63500976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 0.00390625,-0.015869140625 0.00390625,-0.015869140625 c 0.0,0.0 -0.0108337402344,-7.92947387695 -0.0108337402344,-7.92947387695 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="316"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0252990722656,-2.96975708008 c 0.0,0.0 -0.00390625,0.0166320800781 -0.00390625,0.0166320800781 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -1.63500976562,0.0 -1.63500976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.01123046875,7.9296875 0.01123046875,7.9296875 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 1.63500976562,0.0 1.63500976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 0.00390625,-0.015869140625 0.00390625,-0.015869140625 c 0.0,0.0 -0.0108337402344,-7.92947387695 -0.0108337402344,-7.92947387695 Z"
+            android:valueTo="M -5.9959564209,-2.04727172852 c 0.0,0.0 6.01173400879,0.00039672851562 6.01173400879,0.00039672851562 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -6.01000976562,0.0 -6.01000976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.0 0.0,10.0 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 6.01000976562,0.0 6.01000976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 -6.01171875,0.0003662109375 -6.01171875,0.0003662109375 c 0.0,0.0 0.00038146972656,-9.99978637695 0.00038146972656,-9.99978637695 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_4" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_path_3_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_path_3_animation.xml
new file mode 100755
index 0000000..f94fe0a
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_path_3_animation.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="233"
+            android:propertyName="pathData"
+            android:valueFrom="M 5.01239013672,3.390625 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+            android:valueTo="M 5.01239013672,3.390625 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="366"
+            android:propertyName="pathData"
+            android:valueFrom="M 5.01239013672,3.390625 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+            android:valueTo="M 5.00619506836,-6.046875 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@interpolator/error_to_trustedstate_animation_interpolator_2" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/error_to_trustedstate_rectangle_path_1_animation.xml b/packages/SystemUI/res/anim/error_to_trustedstate_rectangle_path_1_animation.xml
new file mode 100755
index 0000000..bcc8c41
--- /dev/null
+++ b/packages/SystemUI/res/anim/error_to_trustedstate_rectangle_path_1_animation.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFF3511E"
+        android:valueTo="#FFFFFFFF"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="1.0"
+        android:valueTo="0.5"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_1_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_1_animation.xml
new file mode 100755
index 0000000..5cf4809
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_1_animation.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="strokeColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="strokeAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="trimPathOffset"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="433"
+            android:propertyName="trimPathOffset"
+            android:valueFrom="1.0"
+            android:valueTo="0.5"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/trusted_state_to_error_animation_interpolator_2" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="trimPathStart"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="433"
+            android:propertyName="trimPathStart"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@interpolator/trusted_state_to_error_animation_interpolator_0" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_2_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_2_animation.xml
new file mode 100755
index 0000000..a387f97
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_ellipse_path_2_animation.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="200"
+        android:propertyName="pathData"
+        android:valueFrom="M 0.0,-1.988645 c 1.09829830627,0.0 1.988645,0.890346693734 1.988645,1.988645 c 0.0,1.09829830627 -0.890346693734,1.988645 -1.988645,1.988645 c -1.09829830627,0.0 -1.988645,-0.890346693734 -1.988645,-1.988645 c 0.0,-1.09829830627 0.890346693734,-1.988645 1.988645,-1.988645 Z"
+        android:valueTo="M 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z"
+        android:valueType="pathType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_exclamation_dot_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_exclamation_dot_animation.xml
new file mode 100755
index 0000000..7a9fb3b
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_exclamation_dot_animation.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="566"
+        android:propertyXName="translateX"
+        android:propertyYName="translateY"
+        android:pathData="M 0.0,4.0 c -0.00065,0.22217 -0.00326,1.11083 -0.00391,1.333"
+        android:interpolator="@interpolator/trusted_state_to_error_animation_interpolator_1" />
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleX"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="300"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleY"
+            android:valueFrom="0.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_lock_left_side_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_lock_left_side_animation.xml
new file mode 100755
index 0000000..2a4753a
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_lock_left_side_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_lock_right_side_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_lock_right_side_animation.xml
new file mode 100755
index 0000000..2a4753a
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_lock_right_side_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.33333"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_lock_top_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_lock_top_animation.xml
new file mode 100755
index 0000000..1f601d3
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_lock_top_animation.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="116"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleX"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="116"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="1.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="16"
+            android:propertyName="scaleY"
+            android:valueFrom="1.0"
+            android:valueTo="0.0"
+            android:valueType="floatType"
+            android:interpolator="@android:interpolator/linear" />
+    </set>
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_path_1_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_path_1_animation.xml
new file mode 100755
index 0000000..7b9be5c
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_path_1_animation.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="pathData"
+            android:valueFrom="M 6.00561523438,-4.046875 c 0.0,0.0 -5.98999023438,0.0 -5.98999023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 5.98812866211,0.0 5.98812866211,0.0 c 0.0,0.0 0.00064086914062,10.0 0.00064086914062,10.0 c 0.0,0.0 -5.98840332031,0.0 -5.98840332031,0.0 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 5.99487304688,0.0 5.99487304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.0 0.0,-10.0 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueTo="M 6.00561523438,-4.046875 c 0.0,0.0 -5.98999023438,0.0 -5.98999023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 5.98812866211,0.0 5.98812866211,0.0 c 0.0,0.0 0.00064086914062,10.0 0.00064086914062,10.0 c 0.0,0.0 -5.98840332031,0.0 -5.98840332031,0.0 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 5.99487304688,0.0 5.99487304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.0 0.0,-10.0 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M 6.00561523438,-4.046875 c 0.0,0.0 -5.98999023438,0.0 -5.98999023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 5.98812866211,0.0 5.98812866211,0.0 c 0.0,0.0 0.00064086914062,10.0 0.00064086914062,10.0 c 0.0,0.0 -5.98840332031,0.0 -5.98840332031,0.0 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 5.99487304688,0.0 5.99487304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.0 0.0,-10.0 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueTo="M 1.63623046875,-4.953125 c 0.0,0.0 -1.61499023438,0.0 -1.61499023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 0.00064086914062,10.625 0.00064086914062,10.625 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 1.61987304688,0.0 1.61987304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.625 0.0,-10.625 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 1.63623046875,-4.953125 c 0.0,0.0 -1.61499023438,0.0 -1.61499023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 0.00064086914062,10.625 0.00064086914062,10.625 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 1.61987304688,0.0 1.61987304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.625 0.0,-10.625 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+            android:valueTo="M 0.02685546875,-4.96875 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 -0.00936889648438,3.9296875 -0.00936889648438,3.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0028076171875,0.0234375 -0.0028076171875,0.0234375 c 0.0,0.0 0.010498046875,-0.015625 0.010498046875,-0.015625 c 0.0,0.0 0.985595703125,0.0078125 0.985595703125,0.0078125 c 0.0,0.0 0.017578125,-6.015625 0.017578125,-6.015625 c 0.0,0.0 0.104400634766,0.0546875 -0.99560546875,0.0546875 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_path_2_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_path_2_animation.xml
new file mode 100755
index 0000000..8eb0c62
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_path_2_animation.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <set
+        android:ordering="sequentially" >
+        <objectAnimator
+            android:duration="33"
+            android:propertyName="pathData"
+            android:valueFrom="M -5.9959564209,-2.04727172852 c 0.0,0.0 6.01173400879,0.00039672851562 6.01173400879,0.00039672851562 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -6.01000976562,0.0 -6.01000976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.0 0.0,10.0 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 6.01000976562,0.0 6.01000976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 -6.01171875,0.0003662109375 -6.01171875,0.0003662109375 c 0.0,0.0 0.00038146972656,-9.99978637695 0.00038146972656,-9.99978637695 Z"
+            android:valueTo="M -5.9959564209,-2.04727172852 c 0.0,0.0 6.01173400879,0.00039672851562 6.01173400879,0.00039672851562 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -6.01000976562,0.0 -6.01000976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.0 0.0,10.0 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 6.01000976562,0.0 6.01000976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 -6.01171875,0.0003662109375 -6.01171875,0.0003662109375 c 0.0,0.0 0.00038146972656,-9.99978637695 0.00038146972656,-9.99978637695 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/linear" />
+        <objectAnimator
+            android:duration="166"
+            android:propertyName="pathData"
+            android:valueFrom="M -5.9959564209,-2.04727172852 c 0.0,0.0 6.01173400879,0.00039672851562 6.01173400879,0.00039672851562 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -6.01000976562,0.0 -6.01000976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.0 0.0,10.0 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 6.01000976562,0.0 6.01000976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 -6.01171875,0.0003662109375 -6.01171875,0.0003662109375 c 0.0,0.0 0.00038146972656,-9.99978637695 0.00038146972656,-9.99978637695 Z"
+            android:valueTo="M 0.0252990722656,-2.96975708008 c 0.0,0.0 -0.00390625,0.0166320800781 -0.00390625,0.0166320800781 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -1.63500976562,0.0 -1.63500976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.625 0.0,10.625 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 1.63500976562,0.0 1.63500976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 0.00390625,-0.015869140625 0.00390625,-0.015869140625 c 0.0,0.0 0.00039672851562,-10.624786377 0.00039672851562,-10.624786377 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+        <objectAnimator
+            android:duration="200"
+            android:propertyName="pathData"
+            android:valueFrom="M 0.0252990722656,-2.96975708008 c 0.0,0.0 -0.00390625,0.0166320800781 -0.00390625,0.0166320800781 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -1.63500976562,0.0 -1.63500976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.625 0.0,10.625 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 1.63500976562,0.0 1.63500976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 0.00390625,-0.015869140625 0.00390625,-0.015869140625 c 0.0,0.0 0.00039672851562,-10.624786377 0.00039672851562,-10.624786377 Z"
+            android:valueTo="M 0.0252990722656,-2.96914672852 c 0.0,0.0 -0.00390625,0.0160217285156 -0.00390625,0.0160217285156 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 0.005615234375,-0.015625 0.005615234375,-0.015625 c -1.10000610352,0.0 -1.01220703125,-0.0546875 -1.01220703125,-0.0546875 c 0.0,0.0 -0.017578125,6.015625 -0.017578125,6.015625 c 0.0,0.0 -0.0777893066406,-0.0078125 1.02221679688,-0.0078125 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 -0.002685546875,-0.0244140625 -0.002685546875,-0.0244140625 c 0.0,0.0 0.00390625,-0.0152587890625 0.00390625,-0.0152587890625 c 0.0,0.0 0.0104064941406,-3.92947387695 0.0104064941406,-3.92947387695 Z"
+            android:valueType="pathType"
+            android:interpolator="@android:interpolator/fast_out_slow_in" />
+    </set>
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_path_3_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_path_3_animation.xml
new file mode 100755
index 0000000..2e86744
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_path_3_animation.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="200"
+        android:propertyName="pathData"
+        android:valueFrom="M 5.00619506836,-6.046875 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+        android:valueTo="M 5.01239013672,3.390625 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+        android:valueType="pathType"
+        android:interpolator="@interpolator/trusted_state_to_error_animation_interpolator_3" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/anim/trusted_state_to_error_rectangle_path_1_animation.xml b/packages/SystemUI/res/anim/trusted_state_to_error_rectangle_path_1_animation.xml
new file mode 100755
index 0000000..46d571c
--- /dev/null
+++ b/packages/SystemUI/res/anim/trusted_state_to_error_rectangle_path_1_animation.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<set
+    xmlns:android="http://schemas.android.com/apk/res/android" >
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillColor"
+        android:valueFrom="#FFFFFFFF"
+        android:valueTo="#FFF3511E"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+    <objectAnimator
+        android:duration="600"
+        android:propertyName="fillAlpha"
+        android:valueFrom="0.5"
+        android:valueTo="1.0"
+        android:valueType="floatType"
+        android:interpolator="@android:interpolator/fast_out_slow_in" />
+</set>
diff --git a/packages/SystemUI/res/drawable/error_to_trustedstate.xml b/packages/SystemUI/res/drawable/error_to_trustedstate.xml
new file mode 100755
index 0000000..6211edf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/error_to_trustedstate.xml
@@ -0,0 +1,84 @@
+<?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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="error_to_trustedstate"
+    android:width="32dp"
+    android:viewportWidth="32"
+    android:height="32dp"
+    android:viewportHeight="32" >
+    <group
+        android:name="error_to_trusted_state"
+        android:translateX="16"
+        android:translateY="16" >
+        <group
+            android:name="error_circle" >
+            <path
+                android:name="ellipse_path_1"
+                android:trimPathStart="0"
+                android:trimPathEnd="1"
+                android:trimPathOffset="0.0"
+                android:strokeColor="#FFF3511E"
+                android:strokeWidth="2"
+                android:pathData="M 0.0,-12.0 c 6.6274169976,0.0 12.0,5.3725830024 12.0,12.0 c 0.0,6.6274169976 -5.3725830024,12.0 -12.0,12.0 c -6.6274169976,0.0 -12.0,-5.3725830024 -12.0,-12.0 c 0.0,-6.6274169976 5.3725830024,-12.0 12.0,-12.0 Z" />
+        </group>
+        <group
+            android:name="middle_ellipse"
+            android:translateY="2.9375" >
+            <path
+                android:name="ellipse_path_2"
+                android:fillColor="#FFF3511E"
+                android:pathData="M 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+        </group>
+        <group
+            android:name="lock_right_side"
+            android:scaleX="1.33333"
+            android:scaleY="1.33333" >
+            <path
+                android:name="path_1"
+                android:pathData="M 0.02685546875,-4.96875 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 0.00375366210938,-0.015625 0.00375366210938,-0.015625 c 0.0,0.0 -0.00936889648438,3.9296875 -0.00936889648438,3.9296875 c 0.0,0.0 -0.0040283203125,0.015625 -0.0040283203125,0.015625 c 0.0,0.0 -0.0028076171875,0.0234375 -0.0028076171875,0.0234375 c 0.0,0.0 0.010498046875,-0.015625 0.010498046875,-0.015625 c 0.0,0.0 0.985595703125,0.0078125 0.985595703125,0.0078125 c 0.0,0.0 0.017578125,-6.015625 0.017578125,-6.015625 c 0.0,0.0 0.104400634766,0.0546875 -0.99560546875,0.0546875 Z"
+                android:fillColor="#FFF3511E" />
+        </group>
+        <group
+            android:name="lock_left_side"
+            android:scaleX="1.33333"
+            android:scaleY="1.33333" >
+            <path
+                android:name="path_2"
+                android:pathData="M 0.0252990722656,-2.96914672852 c 0.0,0.0 -0.00390625,0.0160217285156 -0.00390625,0.0160217285156 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 0.005615234375,-0.015625 0.005615234375,-0.015625 c -1.10000610352,0.0 -1.01220703125,-0.0546875 -1.01220703125,-0.0546875 c 0.0,0.0 -0.017578125,6.015625 -0.017578125,6.015625 c 0.0,0.0 -0.0777893066406,-0.0078125 1.02221679688,-0.0078125 c 0.0,0.0 -0.005615234375,0.015625 -0.005615234375,0.015625 c 0.0,0.0 -0.002685546875,-0.0244140625 -0.002685546875,-0.0244140625 c 0.0,0.0 0.00390625,-0.0152587890625 0.00390625,-0.0152587890625 c 0.0,0.0 0.0104064941406,-3.92947387695 0.0104064941406,-3.92947387695 Z"
+                android:fillColor="#FFF3511E" />
+        </group>
+        <group
+            android:name="lock_top"
+            android:scaleX="0"
+            android:scaleY="0" >
+            <path
+                android:name="path_3"
+                android:pathData="M 5.01239013672,3.390625 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+                android:fillColor="#FFF3511E" />
+        </group>
+        <group
+            android:name="exclamation_dot"
+            android:translateX="-0.00391"
+            android:translateY="5.333" >
+            <path
+                android:name="rectangle_path_1"
+                android:fillColor="#FFF3511E"
+                android:pathData="M -1.33871,-1.3335 l 2.67742,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.667 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.67742,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.667 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/error_to_trustedstate_animation.xml b/packages/SystemUI/res/drawable/error_to_trustedstate_animation.xml
new file mode 100755
index 0000000..6befe13
--- /dev/null
+++ b/packages/SystemUI/res/drawable/error_to_trustedstate_animation.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/error_to_trustedstate" >
+    <target
+        android:name="ellipse_path_1"
+        android:animation="@anim/error_to_trustedstate_ellipse_path_1_animation" />
+    <target
+        android:name="ellipse_path_2"
+        android:animation="@anim/error_to_trustedstate_ellipse_path_2_animation" />
+    <target
+        android:name="lock_right_side"
+        android:animation="@anim/error_to_trustedstate_lock_right_side_animation" />
+    <target
+        android:name="path_1"
+        android:animation="@anim/error_to_trustedstate_path_1_animation" />
+    <target
+        android:name="lock_left_side"
+        android:animation="@anim/error_to_trustedstate_lock_left_side_animation" />
+    <target
+        android:name="path_2"
+        android:animation="@anim/error_to_trustedstate_path_2_animation" />
+    <target
+        android:name="lock_top"
+        android:animation="@anim/error_to_trustedstate_lock_top_animation" />
+    <target
+        android:name="path_3"
+        android:animation="@anim/error_to_trustedstate_path_3_animation" />
+    <target
+        android:name="exclamation_dot"
+        android:animation="@anim/error_to_trustedstate_exclamation_dot_animation" />
+    <target
+        android:name="rectangle_path_1"
+        android:animation="@anim/error_to_trustedstate_rectangle_path_1_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_circle.xml b/packages/SystemUI/res/drawable/ic_qs_circle.xml
new file mode 100644
index 0000000..57223cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_circle.xml
@@ -0,0 +1,30 @@
+<!--
+    Copyright (C) 2015 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="64dp"
+        android:height="64dp"
+        android:viewportWidth="2.2"
+        android:viewportHeight="2.2">
+
+    <path
+        android:strokeColor="#4DFFFFFF"
+        android:strokeWidth=".05"
+        android:pathData="M.1,1.1
+        c0,.55  .45,1   1,1
+        c.55,0  1,-.45  1,-1
+        c0,-.55 -.45,-1 -1,-1
+        c-.55,0 -1,.45  -1,1"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/trusted_state_to_error.xml b/packages/SystemUI/res/drawable/trusted_state_to_error.xml
new file mode 100755
index 0000000..534a9a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/trusted_state_to_error.xml
@@ -0,0 +1,84 @@
+<?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.
+-->
+<vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:name="trusted_state_to_error"
+    android:width="32dp"
+    android:viewportWidth="32"
+    android:height="32dp"
+    android:viewportHeight="32" >
+    <group
+        android:name="trusted_state_to_error_0"
+        android:translateX="16"
+        android:translateY="16" >
+        <group
+            android:name="error_circle" >
+            <path
+                android:name="ellipse_path_1"
+                android:trimPathStart="1"
+                android:trimPathOffset="1"
+                android:strokeColor="#FFFFFFFF"
+                android:strokeAlpha="0.5"
+                android:strokeWidth="2"
+                android:pathData="M 0.0,-12.0 c 6.6274169976,0.0 12.0,5.3725830024 12.0,12.0 c 0.0,6.6274169976 -5.3725830024,12.0 -12.0,12.0 c -6.6274169976,0.0 -12.0,-5.3725830024 -12.0,-12.0 c 0.0,-6.6274169976 5.3725830024,-12.0 12.0,-12.0 Z" />
+        </group>
+        <group
+            android:name="middle_ellipse"
+            android:translateY="2.9375" >
+            <path
+                android:name="ellipse_path_2"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="0.5"
+                android:pathData="M 0.0,-1.988645 c 1.09829830627,0.0 1.988645,0.890346693734 1.988645,1.988645 c 0.0,1.09829830627 -0.890346693734,1.988645 -1.988645,1.988645 c -1.09829830627,0.0 -1.988645,-0.890346693734 -1.988645,-1.988645 c 0.0,-1.09829830627 0.890346693734,-1.988645 1.988645,-1.988645 Z" />
+        </group>
+        <group
+            android:name="lock_right_side" >
+            <path
+                android:name="path_1"
+                android:pathData="M 6.00561523438,-4.046875 c 0.0,0.0 -5.98999023438,0.0 -5.98999023438,0.0 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 5.98812866211,0.0 5.98812866211,0.0 c 0.0,0.0 0.00064086914062,10.0 0.00064086914062,10.0 c 0.0,0.0 -5.98840332031,0.0 -5.98840332031,0.0 c 0.0,0.0 -0.0052490234375,2.0 -0.0052490234375,2.0 c 0.0,0.0 5.99487304688,0.0 5.99487304688,0.0 c 1.10000610352,0.0 2.0,-0.900024414062 2.0,-2.0 c 0.0,0.0 0.0,-10.0 0.0,-10.0 c 0.0,-1.09997558594 -0.899993896484,-2.0 -2.0,-2.0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="0.5" />
+        </group>
+        <group
+            android:name="lock_left_side" >
+            <path
+                android:name="path_2"
+                android:pathData="M -5.9959564209,-2.04727172852 c 0.0,0.0 6.01173400879,0.00039672851562 6.01173400879,0.00039672851562 c 0.0,0.0 -0.00015258789062,-2.0 -0.00015258789062,-2.0 c 0.0,0.0 -6.01000976562,0.0 -6.01000976562,0.0 c -1.10000610352,0.0 -2.0,0.900024414062 -2.0,2.0 c 0.0,0.0 0.0,10.0 0.0,10.0 c 0.0,1.09997558594 0.899993896484,2.0 2.0,2.0 c 0.0,0.0 6.01000976562,0.0 6.01000976562,0.0 c 0.0,0.0 -0.000244140625,-2.0009765625 -0.000244140625,-2.0009765625 c 0.0,0.0 -6.01171875,0.0003662109375 -6.01171875,0.0003662109375 c 0.0,0.0 0.00038146972656,-9.99978637695 0.00038146972656,-9.99978637695 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="0.5" />
+        </group>
+        <group
+            android:name="lock_top" >
+            <path
+                android:name="path_3"
+                android:pathData="M 5.00619506836,-6.046875 c 0.0,-2.76000976562 -2.23999023438,-5.0 -5.0,-5.0 c -2.76000976562,0.0 -5.0,2.23999023438 -5.0,5.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,-1.71002197266 1.38999938965,-3.09997558594 3.10000610352,-3.09997558594 c 1.71000671387,0.0 3.10000610352,1.38995361328 3.10000610352,3.09997558594 c 0.0,0.0 0.0,2.0 0.0,2.0 c 0.0,0.0 1.89999389648,0.0 1.89999389648,0.0 c 0.0,0.0 0.0,-2.0 0.0,-2.0 Z"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="0.5" />
+        </group>
+        <group
+            android:name="exclamation_dot"
+            android:translateY="4"
+            android:scaleX="0"
+            android:scaleY="0" >
+            <path
+                android:name="rectangle_path_1"
+                android:fillColor="#FFFFFFFF"
+                android:fillAlpha="0.5"
+                android:pathData="M -1.33871,-1.3335 l 2.67742,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,2.667 c 0.0,0.0 0.0,0.0 0.0,0.0 l -2.67742,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-2.667 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
+        </group>
+    </group>
+</vector>
diff --git a/packages/SystemUI/res/drawable/trusted_state_to_error_animation.xml b/packages/SystemUI/res/drawable/trusted_state_to_error_animation.xml
new file mode 100755
index 0000000..5686d54
--- /dev/null
+++ b/packages/SystemUI/res/drawable/trusted_state_to_error_animation.xml
@@ -0,0 +1,50 @@
+<?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.
+-->
+<animated-vector
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/trusted_state_to_error" >
+    <target
+        android:name="ellipse_path_1"
+        android:animation="@anim/trusted_state_to_error_ellipse_path_1_animation" />
+    <target
+        android:name="ellipse_path_2"
+        android:animation="@anim/trusted_state_to_error_ellipse_path_2_animation" />
+    <target
+        android:name="lock_right_side"
+        android:animation="@anim/trusted_state_to_error_lock_right_side_animation" />
+    <target
+        android:name="path_1"
+        android:animation="@anim/trusted_state_to_error_path_1_animation" />
+    <target
+        android:name="lock_left_side"
+        android:animation="@anim/trusted_state_to_error_lock_left_side_animation" />
+    <target
+        android:name="path_2"
+        android:animation="@anim/trusted_state_to_error_path_2_animation" />
+    <target
+        android:name="lock_top"
+        android:animation="@anim/trusted_state_to_error_lock_top_animation" />
+    <target
+        android:name="path_3"
+        android:animation="@anim/trusted_state_to_error_path_3_animation" />
+    <target
+        android:name="exclamation_dot"
+        android:animation="@anim/trusted_state_to_error_exclamation_dot_animation" />
+    <target
+        android:name="rectangle_path_1"
+        android:animation="@anim/trusted_state_to_error_rectangle_path_1_animation" />
+</animated-vector>
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
index b2d988e..262cb88
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 0.254777070064,0.0 c 0.00007,0.0 0.447133757962,1.0 0.745222929936,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
index b2d988e..9ecee94
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.00010,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
index b2d988e..ae0b2d7
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.000100000000009,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
index b2d988e..be7cc69
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.00010,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
index b2d988e..f8f978d
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
index b2d988e..9ecee94
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.00010,0.0 0.6,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
index b2d988e..87ef1d4
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 l 0.412907702984,0.0 c 0.00006,0.0 0.35225537821,1.0 0.587092297016,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
old mode 100644
new mode 100755
similarity index 66%
copy from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
copy to packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
index b2d988e..be7cc69
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.00010,0.0 0.2,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
old mode 100644
new mode 100755
similarity index 66%
rename from packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
rename to packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
index b2d988e..83af65a
--- a/packages/SystemUI/res/drawable-anydpi/nav_app_divider.xml
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
 <!--
 Copyright (C) 2015 The Android Open Source Project
 
@@ -13,12 +14,6 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="1dp"
-        android:height="24dp"
-        android:viewportWidth="1"
-        android:viewportHeight="24">
-    <path
-        android:pathData="M0,0 L1,0 L1,24 L0,24 z"
-        android:fillColor="#AAFFFFFF"/>
-</vector>
+<pathInterpolator
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0.0,0.0 c 0.4,0.0 0.9999,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml b/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
index 01c239e..ac95b5e 100644
--- a/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
+++ b/packages/SystemUI/res/layout/navigation_bar_with_apps.xml
@@ -82,21 +82,6 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     />
-
-                <ImageView android:id="@+id/app_divider"
-                    android:focusable="false"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:layout_marginLeft="10dp"
-                    android:layout_marginRight="10dp"
-                    android:src="@drawable/nav_app_divider"
-                    />
-
-                <com.android.systemui.statusbar.phone.NavigationBarRecents
-                    android:layout_width="wrap_content"
-                    android:layout_height="match_parent"
-                    />
             </LinearLayout>
 
             <FrameLayout
@@ -248,21 +233,6 @@
                     android:layout_width="wrap_content"
                     android:layout_height="match_parent"
                     />
-
-                <ImageView android:id="@+id/app_divider"
-                    android:focusable="false"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="center"
-                    android:layout_marginLeft="10dp"
-                    android:layout_marginRight="10dp"
-                    android:src="@drawable/nav_app_divider"
-                    />
-
-            <com.android.systemui.statusbar.phone.NavigationBarRecents
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                />
             </LinearLayout>
 
             <FrameLayout
diff --git a/packages/SystemUI/res/layout/qs_paged_page.xml b/packages/SystemUI/res/layout/qs_paged_page.xml
new file mode 100644
index 0000000..eef08ba
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_paged_page.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+<view
+    class="com.android.systemui.qs.PagedTileLayout$TilePage"
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tile_page"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
new file mode 100644
index 0000000..6c236ea
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -0,0 +1,53 @@
+<?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.
+-->
+
+<com.android.systemui.qs.PagedTileLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <view
+        class="com.android.systemui.qs.PagedTileLayout$FirstPage"
+        android:id="@+id/first_page"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <com.android.systemui.qs.QuickTileLayout
+            android:id="@+id/quick_tile_layout"
+            android:layout_width="match_parent"
+            android:layout_height="@dimen/qs_quick_actions_height"
+            android:orientation="horizontal"
+            android:paddingLeft="@dimen/qs_quick_actions_padding"
+            android:paddingRight="@dimen/qs_quick_actions_padding" />
+
+        <view
+            class="com.android.systemui.qs.PagedTileLayout$TilePage"
+            android:id="@+id/tile_page"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content" />
+
+    </view>
+
+    <com.android.systemui.qs.PageIndicator
+        android:id="@+id/page_indicator"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|bottom"
+        android:gravity="center" />
+
+</com.android.systemui.qs.PagedTileLayout>
diff --git a/packages/SystemUI/res/layout/qs_tile_layout.xml b/packages/SystemUI/res/layout/qs_tile_layout.xml
new file mode 100644
index 0000000..b5d1a1e
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_tile_layout.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<com.android.systemui.qs.TileLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_height="wrap_content"
+    android:layout_width="match_parent" />
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 9294a16..1473f24 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Program is nie op jou toestel geïnstalleer nie"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Wys horlosiesekondes"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Wys horlosiesekondes op die statusbalk. Sal batterylewe dalk beïnvloed."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Herrangskik Kitsinstellings"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Wys helderheid in Kitsinstellings"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Gebruik verdeling in Kitsinstellings"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimenteel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 13f768d..7ab6af9 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"መተግበሪያ በእርስዎ መሣሪያ ላይ አልተጫነም"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"የሰዓት ሰከንዶችን አሳይ"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ፈጣን ቅንብሮችን ዳግም ያደራጁ"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"በፈጣን ቅንብሮች ውስጥ ብሩህነትን አሳይ"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"በፈጣን ቅንብሮች ውስጥ ምልክት መጥሪያን ይጠቀሙ"</string>
+    <string name="experimental" msgid="6198182315536726162">"የሙከራ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6889a43..bd02650 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -439,4 +439,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"التطبيق غير مثبّت على جهازك"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"عرض ثواني الساعة"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"إعادة ترتيب الإعدادات السريعة"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"عرض السطوع في الإعدادات السريعة"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"استخدام ترقيم الصفحات في الإعدادات السريعة"</string>
+    <string name="experimental" msgid="6198182315536726162">"إعدادات تجريبية"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 51513bd..a0d7d2b 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Tətbiq cihazınızda quraşdırılmayıb"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Saatın saniyəsini göstərin"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Saatın saniyəsini status panelində göstərin. Batareyaya təsir edə bilər."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Sürətli Ayarları yenidən tənzimləyin"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Sürətli ayarlarda parlaqlılığı göstərin"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Sürətli Ayarlarda səhifə nömrələməsindən istifadə edin"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 014d802..a14d0fc 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Приложението не е инсталирано на устройството ви"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Показване на секундите на часовника"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Пренареждане на бързите настройки"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Показване на яркостта от бързите настройки"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Използване на разделянето на страници от бързите настройки"</string>
+    <string name="experimental" msgid="6198182315536726162">"Експериментални"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 0860019..e819d54 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"আপনার ডিভাইসে অ্যাপ্লিকেশান ইনস্টল করা নেই"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ঘড়ির সেকেন্ড দেখায়"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"দ্রুত সেটিংসে পুনরায় সাজান"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"দ্রুত সেটিংসে উজ্জ্বলতা দেখান"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"দ্রুত সেটিংসে পেজিং ব্যবহার করুন"</string>
+    <string name="experimental" msgid="6198182315536726162">"পরীক্ষামূলক"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 7dd11eb..7def415f 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -270,7 +270,7 @@
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Emet"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"En emissió"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Dispositiu sense nom"</string>
-    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"A punt per a l\'emissió"</string>
+    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"A punt per emetre"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"No hi ha cap dispositiu disponible."</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Brillantor"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"AUTOMÀTICA"</string>
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Torna a ordenar la Configuració ràpida"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostra la brillantor a la Configuració ràpida"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utilitza la paginació a la Configuració ràpida"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4d96a01..a73947f 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -439,4 +439,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikace není v zařízení nainstalována."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Zobrazit sekundovou ručičku"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Na stavovém řádku se bude zobrazovat sekundová ručička. Může být ovlivněna výdrž baterie."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Změnit uspořádání Rychlého nastavení"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Zobrazit jas v Rychlém nastavení"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Použít v Rychlém nastavení stránkování"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentální"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 7f005a3..6f49187 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Applikationen er ikke installeret på din enhed."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statuslinjen. Dette kan påvirke batteriets levetid."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Omarranger Hurtige indstillinger"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i Hurtige indstillinger"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Brug sidelayout i Hurtige indstillinger"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 36f3c98..a659077 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Die App ist nicht auf Ihrem Gerät installiert."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Uhrsekunden anzeigen"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Uhrsekunden in der Statusleiste anzeigen. Kann sich auf die Akkulaufzeit auswirken."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Schnelleinstellungen neu anordnen"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Helligkeit in den Schnelleinstellungen anzeigen"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Seitenlayout in den Schnelleinstellungen verwenden"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentell"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8e73b21..bcfc458 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Η εφαρμογή δεν έχει εγκατασταθεί στη συσκευή σας"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Εμφάνιση δευτερολέπτων ρολογιού"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Αναδιάταξη Γρήγορων ρυθμίσεων"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Εμφάνιση φωτεινότητας στις Γρήγορες ρυθμίσεις"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Χρήση τηλεειδοποίησης στις Γρήγορες ρυθμίσεις"</string>
+    <string name="experimental" msgid="6198182315536726162">"Σε πειραματικό στάδιο"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 0b49955..fb781d4 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 0b49955..fb781d4 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 0b49955..fb781d4 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Application is not installed on your device"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Show clock seconds"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Show clock seconds in the status bar. May impact battery life."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Rearrange Quick Settings"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Show brightness in Quick Settings"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Use paging in Quick Settings"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index c4dca9c..10834a2 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en el dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar la duración de la batería."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar la Configuración rápida"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar el brillo en la Configuración rápida"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Usar la paginación en la Configuración rápida"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index e316a94..37c81f4 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"La aplicación no está instalada en tu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar los segundos del reloj"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Muestra los segundos del reloj en la barra de estado. Puede afectar a la duración de la batería."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Ajustes rápidos"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Ajustes rápidos"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginación en Ajustes rápidos"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index a151bce..f4218a3 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Rakendust pole teie seadmesse installitud"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Kella sekundite kuvamine"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Olekuribal kella sekundite kuvamine. See võib mõjutada aku kasutusaega."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Korralda kiirseaded ümber"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Kuva kiirseadetes heledus"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Kasuta kiirseadetes lehe paigutust"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentaalne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 37cdee7..fbf0eb42 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikazioa ez dago gailuan instalatuta"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Erakutsi erlojuko segundoak"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Erakutsi erlojuko segundoak egoera-barran. Baliteke bateria gehiago erabiltzea."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Berrantolatu ezarpen bizkorrak"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Erakutsi ezarpen bizkorren distira"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Erabili ezarpen bizkorretako orriak pasatzeko diseinu berria"</string>
+    <string name="experimental" msgid="6198182315536726162">"Esperimentala"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 80d0918..fa01c47 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"برنامه در دستگاه شما نصب نیست"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"نمایش ثانیه‌های ساعت"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ترتیب مجدد در تنظیمات سریع"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"نمایش روشنایی در تنظیمات سریع"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"استفاده از صفحه‌بندی در تنظیمات سریع"</string>
+    <string name="experimental" msgid="6198182315536726162">"آزمایشی"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index b86247a..6c4a029 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Sovellusta ei ole asennettu laitteellesi."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Näytä sekunnit kellossa"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Näytä sekunnit tilapalkin kellossa. Tämä voi vaikuttaa akun kestoon."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Järjestä pika-asetukset uudelleen"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Näytä kirkkaus pika-asetuksissa"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Käytä sivutusta pika-asetuksissa"</string>
+    <string name="experimental" msgid="6198182315536726162">"Kokeellinen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index f99447c..07a2fc3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes sur l\'horloge"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes sur l\'horloge dans la barre d\'état. Cela peut réduire l\'autonomie de la pile."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser les paramètres rapides"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans les paramètres rapides"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utiliser la pagination dans les paramètres rapides"</string>
+    <string name="experimental" msgid="6198182315536726162">"Fonctions expérimentales"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index aada1eb..0aa45ae 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"L\'application n\'est pas installée sur votre appareil."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Afficher les secondes sur l\'horloge"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afficher les secondes dans la barre d\'état. Cela risque de réduire l\'autonomie de la batterie."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Réorganiser la fenêtre de configuration rapide"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Afficher la luminosité dans fenêtre de configuration rapide"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utiliser mise en page dans fenêtre de configuration rapide"</string>
+    <string name="experimental" msgid="6198182315536726162">"Paramètres expérimentaux"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 951809f..ec64f22 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"A aplicación non está instalada no teu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do reloxo"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra os segundos do reloxo na barra de estado. Pode influír na duración da batería."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Configuración rápida"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brillo en Configuración rápida"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paxinación en Configuración rápida"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 02e4e52..e873c95 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"તમારા ઉપકરણ પર એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ઘડિયાળ સેકન્ડ બતાવો"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ઝડપી સેટિંગ્સને ફરીથી ગોઠવો"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ઝડપી સેટિંગ્સમાં તેજ બતાવો"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ઝડપી સેટિંગ્સમાં પૃષ્ઠાંકનનો ઉપયોગ કરો"</string>
+    <string name="experimental" msgid="6198182315536726162">"પ્રાયોગિક"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 3ed090c..83ac46e 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ऐप्लिकेशन आपके डिवाइस पर इंस्टॉल नहीं है"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"घड़ी के सेकंड दिखाएं"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"त्वरित सेटिंग को पुन: व्यवस्थित करें"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"त्वरित सेटिंग में स्क्रीन की रोशनी दिखाएं"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"त्वरित सेटिंग में पेजिंग का उपयोग करें"</string>
+    <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9698aba..b5d9931 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -436,4 +436,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikacija nije instalirana na vašem uređaju"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Prikaži sekunde na satu"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikazuju se sekunde na satu na traci statusa. Može utjecati na trajanje baterije."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Promijeni raspored Brzih postavki"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Prikaži svjetlinu u Brzim postavkama"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Upotrijebi redni broj stranice u Brzim postavkama"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentalno"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 37cb0a8..79390a6 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Az alkalmazás nincs telepítve eszközén."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Másodpercek megjelenítése az órán"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Másodpercek megjelenítése az állapotsor óráján. Ez hatással lehet az akkumulátor üzemidejére."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Gyorsbeállítások átrendezése"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Fényerő megjelenítése a gyorsbeállításokban"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Oldalelrendezés használata a gyorsbeállításokban"</string>
+    <string name="experimental" msgid="6198182315536726162">"Kísérleti"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index e31cf49..9f48b26 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Վերադասավորել Արագ կարգավորումները"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Ցույց տալ պայծառությունն Արագ կարգավորումներում"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Օգտագործել էջերի դասավորությունը Արագ կարգավորումներում"</string>
+    <string name="experimental" msgid="6198182315536726162">"Փորձնական"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index ad8141b..60024115 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang di perangkat"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Tampilkan detik jam"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tampilkan detik jam di bilah status. Dapat memengaruhi masa pakai baterai."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Atur Ulang Setelan Cepat"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Tampilkan kecerahan di Setelan Cepat"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Gunakan pembagian laman di Setelan Cepat"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 02caf17..e8e0530 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Forritið er ekki uppsett í tækinu."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Sýna sekúndur á klukku"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Sýna sekúndur á klukku í stöðustikunni. Getur haft áhrif á endingu rafhlöðu."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Endurraða flýtistillingum"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Sýna birtustig í flýtistillingum"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Nota síðuskoðun í flýtistillingum"</string>
+    <string name="experimental" msgid="6198182315536726162">"Tilraunastillingar"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index ab5d8be..8ee5f07 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Applicazione non installata sul dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostra i secondi nell\'orologio"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra i secondi nell\'orologio nella barra di stato. Ciò potrebbe ridurre la durata della carica della batteria."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Riorganizza Impostazioni rapide"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostra luminosità in Impostazioni rapide"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utilizza nuovo layout in Impostazioni rapide"</string>
+    <string name="experimental" msgid="6198182315536726162">"Sperimentali"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 9dad8aa..e38501d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -437,4 +437,12 @@
     <string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"הצג שניות בשעון"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
+    <!-- no translation found for qs_rearrange (8060918697551068765) -->
+    <skip />
+    <!-- no translation found for show_brightness (6613930842805942519) -->
+    <skip />
+    <!-- no translation found for qs_paging (7020133150248666132) -->
+    <skip />
+    <!-- no translation found for experimental (6198182315536726162) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9cb2fc8..a73f4c1 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"アプリが端末にインストールされていません"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"時計の秒を表示"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"クイック設定を並べ替え"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"クイック設定に明るさ調整バーを表示する"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"クイック設定でページ設定を使用する"</string>
+    <string name="experimental" msgid="6198182315536726162">"試験運用版"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index a9728b2..f1035a8 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"აპლიკაცია თქვენს მოწყობილობაზე დაყენებული არ არის"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"საათის წამების ჩვენება"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"სწრაფი პარამეტრების გადაწყობა"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"სიკაშკაშის ჩვენება სწრაფ პარამეტრებში"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"გამოიყენეთ გვერდების დანომვრა სწრაფ პარამეტრებში"</string>
+    <string name="experimental" msgid="6198182315536726162">"ექსპერიმენტული"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 1d61372..8b82e5f 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Қолданба құрылғыда орнатылмаған"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Сағат секундтарын көрсету"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Жылдам параметрлерді қайта реттеу"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Жылдам параметрлерде жарықтықты көрсету"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Жылдам параметрлерде беттерді нөмірлеуді пайдалану"</string>
+    <string name="experimental" msgid="6198182315536726162">"Эксперименттік"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index c233f83..b8db00f 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"កម្មវិធីមិនបានដំឡើងនៅលើឧបករណ៍របស់អ្នកទេ"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"បង្ហាញវិនាទី"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"រៀបចំការកំណត់រហ័សឡើងវិញ"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"បង្ហាញកម្រិតពន្លឺនៅក្នុងការកំណត់រហ័ស"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ប្រើការចុះទំព័រនៅក្នុងការកំណត់រហ័ស"</string>
+    <string name="experimental" msgid="6198182315536726162">"ពិសោធន៍"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index d486e56..316c04f 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ಗಡಿಯಾರದ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳನ್ನು ಮರುಹೊಂದಿಸಿ"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪ್ರಖರತೆಯನ್ನು ತೋರಿಸಿ"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌‌ಗಳಲ್ಲಿ ಪುಟಗಳನ್ನು ಬಳಸಿ"</string>
+    <string name="experimental" msgid="6198182315536726162">"ಪ್ರಾಯೋಗಿಕ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 3505754..d7f1543 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"기기에 애플리케이션이 설치되어 있지 않습니다."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"시계 초 단위 표시"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"빠른 설정 재정렬"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"빠른 설정에서 밝기 표시"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"빠른 설정에서 페이지 레이아웃 사용"</string>
+    <string name="experimental" msgid="6198182315536726162">"베타"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 968a65a..efe699b 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Колдонмо сиздин түзмөгүңүздө орнотулган эмес"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Сааттын секунддары көрсөтүлсүн"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Ыкчам жөндөөлөрдү кайра коюу"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Ыкчам жөндөөлөрдөн жарыктыгын көрсөтүү"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Ыкчам жөндөөлөрдөн баракты номерлөөнү колдонуу"</string>
+    <string name="experimental" msgid="6198182315536726162">"Сынамык"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index f34c70e..50b4522 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ຖືກ​ຕິດ​ຕັ້ງ​ຢູ່​ໃນ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ຈັດ​ວາງ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ​ຄືນ​ໃໝ່"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ສະ​ແດງ​ຄວາມ​ແຈ້ງ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ໃຊ້​ການ​ໃສ່​ໜ້າ​ຢູ່​ໃນ​ການ​ຕັ້ງ​ຄ່າ​ດ່ວນ"</string>
+    <string name="experimental" msgid="6198182315536726162">"ຍັງຢູ່ໃນການທົດລອງ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index cf70d6b..9082778 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Programa neįdiegta įrenginyje"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Rodyti laikrodžio sekundes"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Rodyti laikrodžio sekundes būsenos juostoje. Tai gali paveikti akumuliatoriaus naudojimo laiką."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Pertvarkyti sparčiuosius nustatymus"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Rodyti skaistį sparčiuosiuose nustatymuose"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Naudoti puslapių kaitą sparčiuosiuose nustatymuose"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentinė versija"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5e2db80..5fb4bb0 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -436,4 +436,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Lietojumprogramma nav instalēta jūsu ierīcē."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Rādīt pulksteņa sekundes"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Statusa joslā rādīt pulksteņa sekundes. Var ietekmēt akumulatora darbības laiku."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Pārkārtot ātros iestatījumus"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Rādīt spilgtumu ātrajos iestatījumos"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Izmantot lapošanu ātrajos iestatījumos"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentāli"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index fe781b6..8571b3f 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Апликацијата не е инсталирана на уредот"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Прикажи ги секундите на часовникот"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Преуредете ги Брзи поставки"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Прикажете ја осветленоста во Брзи поставки"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Користете прелистување страници во Брзи поставки"</string>
+    <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 6e6fc55..4b11962 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"നിങ്ങളുടെ ഉപകരണത്തിൽ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുക"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ദ്രുത ക്രമീകരണം പുനഃസജ്ജീകരിക്കുക"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ദ്രുത ക്രമീകരണത്തിൽ തെളിച്ചം കാണിക്കുക"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ദ്രുത്ര ക്രമീകരണത്തിൽ പേജിംഗ് ഉപയോഗിക്കുക"</string>
+    <string name="experimental" msgid="6198182315536726162">"പരീക്ഷണാത്മകം!"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 65250bb..d1dbd6d 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -433,4 +433,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Апп-ыг таны төхөөрөмжид суулгаагүй байна"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Цагийн секундыг харуулах"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Түргэн тохиргоог дахин засварлах"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Хуудаслалтыг түргэн тохиргоонд ашиглаарай"</string>
+    <string name="experimental" msgid="6198182315536726162">"Туршилтын"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 0f71b4b..fe50f90 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"अनुप्रयोग आपल्या डिव्हाइसवर स्थापित केलेला नाही"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"घड्‍याळ सेकंद दर्शवा"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"दृत सेटिंग्जची पुनर्रचना करा"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"दृत सेटिंग्जमध्‍ये चमक दर्शवा"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिंग्जमध्ये लिखाण वापरा"</string>
+    <string name="experimental" msgid="6198182315536726162">"प्रायोगिक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 596275c..01f7edf 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikasi tidak dipasang pada peranti anda"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Tunjukkan saat jam"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Tunjukkan saat jam dalam bar status. Mungkin menjejaskan hayat bateri."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Susun Semula Tetapan Pantas"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Tunjukkan kecerahan dalam Tetapan Pantas"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Gunakan penghalaman dalam Tetapan Pantas"</string>
+    <string name="experimental" msgid="6198182315536726162">"Percubaan"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 3147d0c..d0eaccf 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"အပလီကေးရှင်းကို သင်၏ ကိရိယာထဲသို့ တပ်ဆင်မပေးရသေးပါ။"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"နာရီ စက္ကန့်များကို ပြရန်"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"အမြန် ဆက်တင်များကို ပြန်စီစဉ်ရန်"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"အမြန် ဆက်တင်များထဲက တောက်ပမှုကို ပြရန်"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"အမြန် ဆက်တင်များထဲတွင် စာမျက်နှာ ပုံစံချမှုကို အသုံးပြုပါ"</string>
+    <string name="experimental" msgid="6198182315536726162">"စမ်းသပ်ရေး"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index f1bfbe1..e582039 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Appen er ikke installert på enheten din"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Vis sekunder på klokken"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Vis sekunder i statusfeltet på klokken. Det kan påvirke batteritiden."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Omorganiser hurtiginnstillingene"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Vis lysstyrke i hurtiginnstillingene"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Bruk sidetall i hurtiginnstillingene"</string>
+    <string name="experimental" msgid="6198182315536726162">"På forsøksstadiet"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 461a15f..c3dc703 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"तपाईँको यन्त्रमा अनुप्रयोग स्थापना भएको छैन"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"घडीमा सेकेन्ड देखाउनुहोस्"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"द्रुत सेटिङहरू पुनः व्यवस्थित गर्नुहोस्"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"द्रुत सेटिङहरूमा उज्यालो देखाउनुहोस्"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"द्रुत सेटिङहरूमा पेजिंग प्रयोग गर्नुहोस्"</string>
+    <string name="experimental" msgid="6198182315536726162">"प्रयोगात्मक"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index b74f91d..13f02d5 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Deze app is niet geïnstalleerd op uw apparaat"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Klokseconden weergeven"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Klokseconden op de statusbalk weergeven. Kan van invloed zijn op de accuduur."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Snelle instellingen opnieuw indelen"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Helderheid weergeven in Snelle instellingen"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Paginering gebruiken in Snelle instellingen"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimenteel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 06746cc..ef3d2f3 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ਐਪਲੀਕੇਸ਼ਨ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਨੂੰ ਦੁਬਾਰਾ ਕ੍ਰਮ ਦਿਓ"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਚਮਕ ਦਿਖਾਓ"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਪੇਜਿੰਗ ਵਰਤੋ"</string>
+    <string name="experimental" msgid="6198182315536726162">"ਪ੍ਰਯੋਗਾਤਮਿਕ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 66100c1..8c2c5c4 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikacja nie jest zainstalowana na urządzeniu"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Pokaż sekundy na zegarku"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Pokaż sekundy na zegarku na pasku stanu. Może mieć wpływ na czas pracy baterii."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Uporządkuj Szybkie ustawienia"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Pokaż jasność w Szybkich ustawieniach"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Użyj stronicowania w Szybkich ustawieniach"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperymentalne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 53cea01..3803b81 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 5006413..be42e8a 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"A aplicação não está instalada no dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de estado. Pode afetar a autonomia da bateria."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar Definições rápidas"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar luminosidade nas Definições rápidas"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Utilizar paginação nas Definições rápidas"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimental"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 53cea01..3803b81 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"O app não está instalado no seu dispositivo"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostrar segundos do relógio"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostrar segundos do relógio na barra de status. Pode afetar a duração da bateria."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Reorganizar \"Configurações rápidas\""</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Mostrar brilho nas \"Configurações rápidas\""</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Usar paginação nas \"Configurações rápidas\""</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentais"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index d97e16b..bb8f2c3 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -436,4 +436,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplicația nu este instalată pe dispozitiv"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Afișează secundele pe ceas"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Afișează secundele pe ceas în bara de stare. Poate afecta autonomia bateriei."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Rearanjați Setările rapide"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Afișați luminozitatea în Setările rapide"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Folosiți paginarea în Setările rapide"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentale"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index d67ad38..9609f40 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -269,7 +269,7 @@
     <string name="quick_settings_wifi_no_network" msgid="2221993077220856376">"Нет сети"</string>
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi выкл."</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Не удалось найти доступные сети Wi-Fi"</string>
-    <string name="quick_settings_cast_title" msgid="7709016546426454729">"Wi-Fi-монитор"</string>
+    <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляция"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Передача изображения"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Безымянное устройство"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово к передаче"</string>
@@ -439,4 +439,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Приложение не установлено на вашем устройстве"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Показывать секунды"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Изменить порядок Быстрых настроек"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Добавить яркость в Быстрые настройки"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Разбить Быстрые настройки на страницы"</string>
+    <string name="experimental" msgid="6198182315536726162">"Экспериментальная функция"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 06cb626..9e78834 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"යෙදුම ඔබේ උපාංගය මත ස්ථාපනය කර නැත"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"ඔරලෝසු තත්පර පෙන්වන්න"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"ඉක්මන් සැකසීම් යළි පිළිවෙළට සකසන්න"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"ඉක්මන් සැකසීම්වල දීප්තිය පෙන්වන්න"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ඉක්මන් සැකසීම්වල පිටු පිරිසැලසුම් භාවිත කරන්න"</string>
+    <string name="experimental" msgid="6198182315536726162">"පරීක්ෂණාත්මක"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 037074b..e3f0fb3 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -439,4 +439,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikácia nie je nainštalovaná na zariadení"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Zobraziť sekundy"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Zobrazí sekundy v stavovom riadku. Môže to ovplyvňovať výdrž batérie."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Zmeniť usporiadanie Rýchlych nastavení"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Zobraziť jas v Rýchlych nastaveniach"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Použite stránkovanie v Rýchlych nastaveniach"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentálne"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 31fe5d8..4dffcfa 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikacija ni nameščena v napravi"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Prikaz sekund pri uri"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Prikaže sekunde pri uri v vrstici stanja. To lahko vpliva na čas delovanja pri akumulatorskem napajanju."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Preuredi hitre nastavitve"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Prikaz svetlosti v hitrih nastavitvah"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Uporaba postavitve strani v hitrih nastavitvah"</string>
+    <string name="experimental" msgid="6198182315536726162">"Poskusno"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index ffb8bea..20c3426 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Aplikacioni nuk është instaluar në pajisjen tënde."</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Trego sekondat e orës"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Trego sekondat e orës në shiritin e statusit. Mund të ndikojë te jeta e baterisë."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Risistemo Cilësimet e shpejta"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Shfaq ndriçimin te Cilësimet e shpejta"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Përdor faqosjen te Cilësimet e shpejta"</string>
+    <string name="experimental" msgid="6198182315536726162">"Eksperimentale"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index bae0284..1dcde3a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -436,4 +436,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Апликација није инсталирана на уређају"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Приказуј секунде на сату"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Преуреди Брза подешавања"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Прикажи осветљеност у Брзим подешавањима"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Користи листање страница у Брзим подешавањима"</string>
+    <string name="experimental" msgid="6198182315536726162">"Експериментално"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 6588f10..0abeb1e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Appen är inte installerad på enheten"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Visa klocksekunder"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Visa klocksekunder i statusfältet. Detta kan påverka batteritiden."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Ordna snabbinställningarna"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Visa ljusstyrka i snabbinställningarna"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Använd sidindelning i snabbinställningarna"</string>
+    <string name="experimental" msgid="6198182315536726162">"Experimentella"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 623f12c..d000004 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Programu haijasakinishwa kwenye kifaa chako"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Onyesha sekunde za saa"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Onyesha sekunde za saa katika sehemu ya arifa. Inaweza kuathiri muda wa matumizi ya betri."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Panga Upya Mipangilio ya Haraka"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Onyesha unga\'avu katika Mipangilio ya Haraka"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Tumia nambari za ukurasa katika Mipangilio ya Haraka"</string>
+    <string name="experimental" msgid="6198182315536726162">"Ya majaribio"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index c6cb337..7b1ded3 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"சாதனத்தில் பயன்பாடு நிறுவப்படவில்லை"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"கடிகார வினாடிகளைக் காட்டு"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"விரைவு அமைப்புகளை மறுவரிசைப்படுத்து"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"விரைவு அமைப்புகளில் ஒளிர்வுப் பட்டியைக் காட்டு"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"விரைவு அமைப்புகளில் புதிய பக்கத் தளவமைப்பைப் பயன்படுத்து"</string>
+    <string name="experimental" msgid="6198182315536726162">"சோதனை முயற்சி"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index c0717c1..06762bd 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"అనువర్తనం మీ పరికరంలో ఇన్‌స్టాల్ చేయలేదు"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"గడియారం సెకన్లు చూపు"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"శీఘ్ర సెట్టింగ్‌ల ఏర్పాటు క్రమం మార్చు"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"శీఘ్ర సెట్టింగ్‌ల్లో ప్రకాశం చూపు"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"శీఘ్ర సెట్టింగ్‌ల్లో పేజింగ్‌ను ఉపయోగించు"</string>
+    <string name="experimental" msgid="6198182315536726162">"ప్రయోగాత్మకం"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e16fdd2..52c7af7 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ยังไม่ได้ติดตั้งแอปพลิเคชันบนอุปกรณ์ของคุณ"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"แสดงวินาทีของนาฬิกา"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"จัดเรียงการตั้งค่าด่วนใหม่"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"แสดงความสว่างในการตั้งค่าด่วน"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"ใช้การแบ่งหน้าในการตั้งค่าด่วน"</string>
+    <string name="experimental" msgid="6198182315536726162">"ทดสอบ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index d970084..66056d1 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Hindi naka-install ang application sa iyong device"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Ipakita ang mga segundo ng orasan"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Ipakita ang mga segundo ng orasan sa status bar. Maaaring makaapekto sa tagal ng baterya."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Ayusing Muli ang Mga Mabilisang Setting"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Ipakita ang liwanag sa Mga Mabilisang Setting"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Gamitin ang paging sa Mga Mabilisang Setting"</string>
+    <string name="experimental" msgid="6198182315536726162">"Pang-eksperimento"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index b22b4fb..fdad0d5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Uygulama, cihazınızda yüklü değil"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Saatin saniyelerini göster"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Durum çubuğunda saatin saniyelerini gösterir. Pil ömrünü etkileyebilir."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Hızlı Ayarlar\'ı Yeniden Düzenle"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Hızlı Ayarlar\'da parlaklığı göster"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Hızlı Ayarlar\'da sayfa ayırmayı kullan"</string>
+    <string name="experimental" msgid="6198182315536726162">"Deneysel"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 5c0966c..9dde801 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -270,7 +270,7 @@
     <string name="quick_settings_cast_title" msgid="7709016546426454729">"Трансляція"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Трансляція"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Пристрій без назви"</string>
-    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Можна транслювати"</string>
+    <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Готово до трансляції"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="311785821261640623">"Немає пристроїв"</string>
     <string name="quick_settings_brightness_dialog_title" msgid="8599674057673605368">"Яскравість"</string>
     <string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="5064982743784071218">"АВТО"</string>
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Додаток не встановлено на вашому пристрої"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Показувати секунди на годиннику"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Упорядкувати швидкі налаштування"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Показувати панель яскравості у швидких налаштуваннях"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Показувати швидкі налаштування у вигляді сторінок"</string>
+    <string name="experimental" msgid="6198182315536726162">"Експериментальні налаштування"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index d5683e1..a4ef16a 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"ایپلیکیشن آپ کے آلہ پر انسٹال نہیں ہے"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"گھڑی کے سیکنڈز دکھائیں"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"فوری ترتیبات کو دوبارہ ترتیب دیں"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"فوری ترتیبات میں چمکیلا پن دکھائیں"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"فوری ترتیبات میں پیجنگ استعمال کریں"</string>
+    <string name="experimental" msgid="6198182315536726162">"تجرباتی"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index e31af6b..118c4b8 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Ilova qurilmangizga o‘rnatilmagan"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Soat soniyalari ko‘rsatilsin"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Holat panelida soat soniyalari ko‘rsatilsin. Bu batareya resursiga ta’sir qilishi mumkin."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Tezkor sozlamalarni qayta tartiblash"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Tezkor sozlamalarda yorqinlikni ko‘rsatish"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Tezkor sozlamalarda peyjingdan foydalanish"</string>
+    <string name="experimental" msgid="6198182315536726162">"Tajribaviy"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 030bbbe..460d57a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Ứng dụng chưa được cài đặt trên thiết bị của bạn"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Hiển thị giây đồng hồ"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Hiển thị giây đồng hồ trong thanh trạng thái. Có thể ảnh hưởng đến thời lượng pin."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Sắp xếp lại Cài đặt nhanh"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Hiển thị độ sáng trong Cài đặt nhanh"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Sử dụng đánh số trang trong Cài đặt nhanh"</string>
+    <string name="experimental" msgid="6198182315536726162">"Thử nghiệm"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b046415..05644e7 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -437,4 +437,12 @@
     <string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
+    <!-- no translation found for qs_rearrange (8060918697551068765) -->
+    <skip />
+    <!-- no translation found for show_brightness (6613930842805942519) -->
+    <skip />
+    <!-- no translation found for qs_paging (7020133150248666132) -->
+    <skip />
+    <!-- no translation found for experimental (6198182315536726162) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index d568dba..f7cac90 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"尚未在裝置安裝應用程式"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"在快速設定顯示亮度"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"在快速設定使用分頁"</string>
+    <string name="experimental" msgid="6198182315536726162">"實驗版"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 702ad53..369172f 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -437,4 +437,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"您的裝置未安裝這個應用程式"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"重新排列快速設定"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"在快速設定中顯示亮度"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"在快速設定中使用分頁功能"</string>
+    <string name="experimental" msgid="6198182315536726162">"實驗性"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 8774036..2a14a9f 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -435,4 +435,8 @@
     <string name="activity_not_found" msgid="348423244327799974">"Uhlelo lokusebenza alufakiwe kudivayisi yakho"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Bonisa amasekhondi wewashi"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Bonisa amasekhondi wewashi kubha yesimo. Ingathinta impilo yebhethri."</string>
+    <string name="qs_rearrange" msgid="8060918697551068765">"Hlela kabusha izilungiselelo ezisheshayo"</string>
+    <string name="show_brightness" msgid="6613930842805942519">"Bonisa ukukhanya kuzilungiselelo ezisheshayo"</string>
+    <string name="qs_paging" msgid="7020133150248666132">"Sebenzisa i-paging kuzilungiselelo ezisheshayo"</string>
+    <string name="experimental" msgid="6198182315536726162">"Okokulinga"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 527248c..c070a0e 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -90,5 +90,9 @@
     <declare-styleable name="AlphaOptimizedImageView">
         <attr name="hasOverlappingRendering" format="boolean" />
     </declare-styleable>
+
+    <declare-styleable name="TunerSwitch">
+        <attr name="defValue" format="boolean" />
+    </declare-styleable>
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 03ea73c..3817741 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -164,6 +164,9 @@
     <dimen name="pull_span_min">25dp</dimen>
 
     <dimen name="qs_tile_height">88dp</dimen>
+    <dimen name="qs_quick_actions_height">88dp</dimen>
+    <dimen name="qs_quick_actions_padding">25dp</dimen>
+    <dimen name="qs_page_indicator_size">12dp</dimen>
     <dimen name="qs_tile_icon_size">24dp</dimen>
     <dimen name="qs_tile_text_size">12sp</dimen>
     <dimen name="qs_tile_divider_height">1dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 8b3f2d8..b732e99 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1145,4 +1145,15 @@
     <!-- Description of setting to show clock seconds [CHAR LIMIT=NONE] -->
     <string name="clock_seconds_desc">Show clock seconds in the status bar. May impact battery life.</string>
 
+    <!-- Button that leads to page to rearrange quick settings tiles [CHAR LIMIT=60] -->
+    <string name="qs_rearrange">Rearrange Quick Settings</string>
+    <!-- Option to show brightness bar in quick settings [CHAR LIMIT=60] -->
+    <string name="show_brightness">Show brightness in Quick Settings</string>
+    <!-- Option to use new paging layout in quick settings [CHAR LIMIT=60] -->
+    <string name="qs_paging">Use paging in Quick Settings</string>
+
+    <!-- Category in the System UI Tuner settings, where new/experimental
+         settings are -->
+    <string name="experimental">Experimental</string>
+
 </resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index beb863c..5980108 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -15,11 +15,32 @@
 -->
 
 <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:sysui="http://schemas.android.com/apk/res-auto"
     android:title="@string/system_ui_tuner">
 
-    <Preference
-        android:key="qs_tuner"
-        android:title="@string/quick_settings" />
+    <PreferenceScreen
+        android:title="@string/quick_settings">
+
+        <Preference
+            android:key="qs_tuner"
+            android:title="@string/qs_rearrange" />
+
+        <PreferenceCategory
+            android:title="@string/experimental">
+
+            <com.android.systemui.tuner.TunerSwitch
+                android:key="qs_show_brightness"
+                android:title="@string/show_brightness"
+                sysui:defValue="true" />
+
+            <com.android.systemui.tuner.QSPagingSwitch
+                android:key="qs_paged_panel"
+                android:title="@string/qs_paging" />
+
+        </PreferenceCategory>
+
+    </PreferenceScreen>
+
 
     <PreferenceScreen
         android:title="@string/status_bar" >
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 12d5f36..0be3069 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1051,6 +1051,7 @@
                 // Without this, settings is not enabled until the lock screen first appears
                 setShowingLocked(false);
                 hideLocked();
+                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
                 return;
             }
         }
@@ -1461,6 +1462,15 @@
             }
             mHiding = false;
 
+            if (mWakeAndUnlocking && mDrawnCallback != null) {
+
+                // Hack level over 9000: To speed up wake-and-unlock sequence, force it to report
+                // the next draw from here so we don't have to wait for window manager to signal
+                // this to our ViewRootImpl.
+                mStatusBarKeyguardViewManager.getViewRootImpl().setReportNextDraw();
+                notifyDrawn(mDrawnCallback);
+            }
+
             // only play "unlock" noises if not on a call (since the incall UI
             // disables the keyguard)
             if (TelephonyManager.EXTRA_STATE_IDLE.equals(mPhoneState)) {
@@ -1474,9 +1484,6 @@
             updateActivityLockScreenState();
             adjustStatusBarLocked();
             sendUserPresentBroadcast();
-            if (mWakeAndUnlocking && mDrawnCallback != null) {
-                notifyDrawn(mDrawnCallback);
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
new file mode 100644
index 0000000..1200266
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -0,0 +1,86 @@
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import com.android.systemui.R;
+
+public class PageIndicator extends LinearLayout {
+
+    private final int mPageIndicatorSize;
+
+    public PageIndicator(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setGravity(Gravity.CENTER);
+        mPageIndicatorSize =
+                (int) mContext.getResources().getDimension(R.dimen.qs_page_indicator_size);
+    }
+
+    public void setNumPages(int numPages) {
+        while (numPages < getChildCount()) {
+            removeViewAt(getChildCount() - 1);
+        }
+        while (numPages > getChildCount()) {
+            SinglePageIndicator v = new SinglePageIndicator(mContext);
+            v.setAmount(0);
+            addView(v, new LayoutParams(mPageIndicatorSize, mPageIndicatorSize));
+        }
+    }
+
+    public void setLocation(float location) {
+        int index = (int) location;
+        location -= index;
+
+        final int N = getChildCount();
+        for (int i = 0; i < N; i++) {
+            float amount = 0;
+            if (i == index) {
+                amount = 1 - location;
+            } else if (i == index + 1) {
+                amount = location;
+            }
+            ((SinglePageIndicator) getChildAt(i)).setAmount(amount);
+        }
+    }
+
+    // This could be done with a circle drawable and an ImageView, but this seems
+    // easier for now.
+    public static class SinglePageIndicator extends View {
+        private static final int MIN_ALPHA = 0x4d;
+        private static final int MAX_ALPHA = 0xff;
+
+        private static final float MIN_SIZE = .55f;
+        private static final float MAX_SIZE = .7f;
+
+        private final Paint mPaint;
+        private float mSize;
+
+        public SinglePageIndicator(Context context) {
+            super(context);
+            mPaint = new Paint();
+            mPaint.setColor(0xffffffff);
+            mPaint.setAlpha(MAX_ALPHA);
+        }
+
+        public void setAmount(float amount) {
+            mSize = amount * (MAX_SIZE - MIN_SIZE) + MIN_SIZE;
+            int alpha = (int) (amount * (MAX_ALPHA - MIN_ALPHA)) + MIN_ALPHA;
+            mPaint.setAlpha(alpha);
+            postInvalidate();
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            int minDimen = Math.min(getWidth(), getHeight()) / 2;
+            float radius = mSize * minDimen;
+            float x = getWidth() / 2f;
+            float y = getHeight() / 2f;
+            canvas.drawCircle(x, y, radius, mPaint);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
new file mode 100644
index 0000000..ece7022
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -0,0 +1,221 @@
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.internal.widget.PagerAdapter;
+import com.android.internal.widget.ViewPager;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
+import com.android.systemui.qs.QSPanel.TileRecord;
+
+import java.util.ArrayList;
+
+public class PagedTileLayout extends ViewPager implements QSTileLayout {
+
+    private static final boolean DEBUG = false;
+
+    private static final String TAG = "PagedTileLayout";
+
+    private final ArrayList<TileRecord> mTiles = new ArrayList<TileRecord>();
+    private final ArrayList<TilePage> mPages = new ArrayList<TilePage>();
+
+    private FirstPage mFirstPage;
+    private PageIndicator mPageIndicator;
+
+    private int mNumPages;
+
+    public PagedTileLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setAdapter(mAdapter);
+        setOnPageChangeListener(new OnPageChangeListener() {
+            @Override
+            public void onPageSelected(int position) {
+                if (mPageIndicator == null) return;
+                mPageIndicator.setLocation(position);
+            }
+
+            @Override
+            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
+                if (mPageIndicator == null) return;
+                mPageIndicator.setLocation(position + positionOffset);
+            }
+
+            @Override
+            public void onPageScrollStateChanged(int state) {
+            }
+        });
+        setCurrentItem(0);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mPageIndicator = (PageIndicator) findViewById(R.id.page_indicator);
+        ((LayoutParams) mPageIndicator.getLayoutParams()).isDecor = true;
+
+        mFirstPage = (FirstPage) findViewById(R.id.first_page);
+        removeView(mFirstPage); // We don't actually want this on the view yet, just inflated.
+        mPages.add(mFirstPage.mTilePage);
+    }
+
+    @Override
+    public int getOffsetTop(TileRecord tile) {
+        if (tile.tileView.getParent() == mFirstPage.mTilePage) {
+            return mFirstPage.getTop() + mFirstPage.mTilePage.getTop();
+        }
+        return ((ViewGroup) tile.tileView.getParent()).getTop();
+    }
+
+    @Override
+    public void setTileVisibility(TileRecord tile, int visibility) {
+        tile.tileView.setVisibility(visibility);
+        // TODO: Do something smarter here.
+        distributeTiles();
+    }
+
+    @Override
+    public void addTile(TileRecord tile) {
+        mTiles.add(tile);
+        distributeTiles();
+    }
+
+    @Override
+    public void removeTile(TileRecord tile) {
+        if (mTiles.remove(tile)) {
+            distributeTiles();
+        }
+    }
+
+    private void distributeTiles() {
+        if (DEBUG) Log.d(TAG, "Distributing tiles");
+        mFirstPage.mQuickQuickTiles.removeAllViews();
+        final int NP = mPages.size();
+        for (int i = 0; i < NP; i++) {
+            mPages.get(i).clear();
+        }
+        int index = 0;
+        final int NT = mTiles.size();
+        for (int i = 0; i < NT; i++) {
+            TileRecord tile = mTiles.get(i);
+            if (tile.tile.getTileType() == QSTileView.QS_TYPE_QUICK) {
+                tile.tileView.setType(QSTileView.QS_TYPE_QUICK);
+                mFirstPage.mQuickQuickTiles.addView(tile.tileView);
+                continue;
+            }
+            if (mPages.get(index).isFull()) {
+                if (++index == mPages.size()) {
+                    if (DEBUG) Log.d(TAG, "Adding page for " + tile.tile.getClass().getSimpleName());
+                    mPages.add((TilePage) LayoutInflater.from(mContext)
+                            .inflate(R.layout.qs_paged_page, this, false));
+                }
+            }
+            if (DEBUG) Log.d(TAG, "Adding " + tile.tile.getClass().getSimpleName() + " to "
+                    + index);
+            mPages.get(index).addTile(tile);
+        }
+        if (mNumPages != index + 1) {
+            mNumPages = index + 1;
+            mPageIndicator.setNumPages(mNumPages);
+            mAdapter.notifyDataSetChanged();
+        }
+    }
+
+    @Override
+    public void updateResources() {
+        for (int i = 0; i < mPages.size(); i++) {
+            mPages.get(i).updateResources();
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        // The ViewPager likes to eat all of the space, instead force it to wrap to the max height
+        // of the pages.
+        int maxHeight = 0;
+        final int N = getChildCount();
+        for (int i = 0; i < N; i++) {
+            int height = getChildAt(i).getMeasuredHeight();
+            if (height > maxHeight) {
+                maxHeight = height;
+            }
+        }
+        setMeasuredDimension(getMeasuredWidth(), maxHeight + mPageIndicator.getMeasuredHeight());
+    }
+
+    public static class FirstPage extends LinearLayout {
+        private LinearLayout mQuickQuickTiles;
+        private TilePage mTilePage;
+
+        public FirstPage(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @Override
+        protected void onFinishInflate() {
+            super.onFinishInflate();
+            mQuickQuickTiles = (LinearLayout) findViewById(R.id.quick_tile_layout);
+            mTilePage = (TilePage) findViewById(R.id.tile_page);
+            // Less rows on first page, because it needs room for the quick tiles.
+            mTilePage.mMaxRows = 3;
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            // The ViewPager will try to make us taller, don't do it unless we need to.
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
+                    MeasureSpec.AT_MOST);
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+        }
+    }
+
+    public static class TilePage extends TileLayout {
+        private int mMaxRows = 4;
+
+        public TilePage(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            mAllowDual = false;
+        }
+
+        private void clear() {
+            if (DEBUG) Log.d(TAG, "Clearing page");
+            removeAllViews();
+            mRecords.clear();
+        }
+
+        private boolean isFull() {
+            return mRecords.size() >= mColumns * mMaxRows;
+        }
+    }
+
+    private final PagerAdapter mAdapter = new PagerAdapter() {
+        public void destroyItem(ViewGroup container, int position, Object object) {
+            if (DEBUG) Log.d(TAG, "Destantiating " + position);
+            // TODO: Find way to clean up the extra pages.
+            container.removeView((View) object);
+        }
+
+        public Object instantiateItem(ViewGroup container, int position) {
+            if (DEBUG) Log.d(TAG, "Instantiating " + position);
+            ViewGroup view = position == 0 ? mFirstPage : mPages.get(position);
+            container.addView(view);
+            return view;
+        }
+
+        @Override
+        public int getCount() {
+            return mNumPages;
+        }
+
+        @Override
+        public boolean isViewFromObject(View view, Object object) {
+            return view == object;
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index b640cf1..683af97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -43,12 +43,17 @@
 import com.android.systemui.settings.ToggleSlider;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.statusbar.policy.BrightnessMirrorController;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
 /** View that represents the quick settings tile panel. **/
-public class QSPanel extends FrameLayout {
+public class QSPanel extends FrameLayout implements Tunable {
+
+    public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
+    public static final String QS_PAGED_PANEL = "qs_paged_panel";
 
     private final Context mContext;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -75,7 +80,7 @@
     private boolean mGridContentVisible = true;
 
     private LinearLayout mQsContainer;
-    private TileLayout mTileLayout;
+    private QSTileLayout mTileLayout;
 
     public QSPanel(Context context) {
         this(context, null);
@@ -104,10 +109,7 @@
 
         addView(mQsContainer);
 
-        mTileLayout = new TileLayout(mContext, mRecords);
-
         mQsContainer.addView(mBrightnessView);
-        mQsContainer.addView(mTileLayout);
         mQsContainer.addView(mFooter.getView());
         mClipper = new QSDetailClipper(mDetail);
         updateResources();
@@ -126,6 +128,41 @@
         });
     }
 
+    @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TunerService.get(mContext).addTunable(this, QS_SHOW_BRIGHTNESS, QS_PAGED_PANEL);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        TunerService.get(mContext).removeTunable(this);
+        super.onDetachedFromWindow();
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (QS_SHOW_BRIGHTNESS.equals(key)) {
+            mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
+                    ? VISIBLE : GONE);
+        } else if (QS_PAGED_PANEL.equals(key)) {
+            if (mTileLayout != null) {
+                for (int i = 0; i < mRecords.size(); i++) {
+                    mTileLayout.removeTile(mRecords.get(i));
+                }
+                mQsContainer.removeView((View) mTileLayout);
+            }
+            int layout = newValue != null && Integer.parseInt(newValue) != 0
+                    ? R.layout.qs_paged_tile_layout : R.layout.qs_tile_layout;
+            mTileLayout =
+                    (QSTileLayout) LayoutInflater.from(mContext).inflate(layout, mQsContainer, false);
+            mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */);
+            for (int i = 0; i < mRecords.size(); i++) {
+                mTileLayout.addTile(mRecords.get(i));
+            }
+        }
+    }
+
     private void updateDetailText() {
         mDetailDoneButton.setText(R.string.quick_settings_done);
         mDetailSettingsButton.setText(R.string.quick_settings_more_settings);
@@ -164,7 +201,9 @@
             refreshAllTiles();
         }
         updateDetailText();
-        mTileLayout.updateResources();
+        if (mTileLayout != null) {
+            mTileLayout.updateResources();
+        }
     }
 
     @Override
@@ -240,18 +279,18 @@
         mHandler.obtainMessage(H.SHOW_DETAIL, show ? 1 : 0, 0, r).sendToTarget();
     }
 
-    private void setTileVisibility(View v, int visibility) {
-        mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visibility, 0, v).sendToTarget();
+    private void setTileVisibility(TileRecord record, int visibility) {
+        mHandler.obtainMessage(H.SET_TILE_VISIBILITY, visibility, 0, record).sendToTarget();
     }
 
-    private void handleSetTileVisibility(View v, int visibility) {
-        if (visibility == v.getVisibility()) return;
-        v.setVisibility(visibility);
+    private void handleSetTileVisibility(TileRecord tile, int visibility) {
+        if (visibility == tile.tileView.getVisibility()) return;
+        mTileLayout.setTileVisibility(tile, visibility);
     }
 
     public void setTiles(Collection<QSTile<?>> tiles) {
         for (TileRecord record : mRecords) {
-            removeView(record.tileView);
+            mTileLayout.removeTile(record);
         }
         mRecords.clear();
         for (QSTile<?> tile : tiles) {
@@ -264,7 +303,7 @@
 
     private void drawTile(TileRecord r, QSTile.State state) {
         final int visibility = state.visible ? VISIBLE : GONE;
-        setTileVisibility(r.tileView, visibility);
+        setTileVisibility(r, visibility);
         r.tileView.onStateChanged(state);
     }
 
@@ -329,7 +368,9 @@
         r.tile.refreshState();
         mRecords.add(r);
 
-        mTileLayout.addView(r.tileView);
+        if (mTileLayout != null) {
+            mTileLayout.addTile(r);
+        }
     }
 
     public boolean isShowingDetail() {
@@ -371,7 +412,7 @@
         }
         r.tile.setDetailListening(show);
         int x = r.tileView.getLeft() + r.tileView.getWidth() / 2;
-        int y = r.tileView.getTop() + mTileLayout.getTop() + r.tileView.getHeight() / 2;
+        int y = r.tileView.getTop() + mTileLayout.getOffsetTop(r) + r.tileView.getHeight() / 2;
         handleShowDetailImpl(r, show, x, y);
     }
 
@@ -474,7 +515,7 @@
             if (msg.what == SHOW_DETAIL) {
                 handleShowDetail((Record)msg.obj, msg.arg1 != 0);
             } else if (msg.what == SET_TILE_VISIBILITY) {
-                handleSetTileVisibility((View)msg.obj, msg.arg1);
+                handleSetTileVisibility((TileRecord) msg.obj, msg.arg1);
             }
         }
     }
@@ -534,4 +575,12 @@
         void onToggleStateChanged(boolean state);
         void onScanStateChanged(boolean state);
     }
+
+    public interface QSTileLayout {
+        void addTile(TileRecord tile);
+        void removeTile(TileRecord tile);
+        void setTileVisibility(TileRecord tile, int visibility);
+        int getOffsetTop(TileRecord tile);
+        void updateResources();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index b330582..9b3372c3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -83,9 +83,13 @@
         mContext = host.getContext();
         mHandler = new H(host.getLooper());
     }
+    
+    public int getTileType() {
+        return QSTileView.QS_TYPE_NORMAL;
+    }
 
-    public boolean supportsDualTargets() {
-        return false;
+    public final boolean supportsDualTargets() {
+        return getTileType() == QSTileView.QS_TYPE_DUAL;
     }
 
     public Host getHost() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 6d26a3b..08cdc1e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -48,6 +48,10 @@
     private static final Typeface CONDENSED = Typeface.create("sans-serif-condensed",
             Typeface.NORMAL);
 
+    public static final int QS_TYPE_NORMAL = 0;
+    public static final int QS_TYPE_DUAL   = 1;
+    public static final int QS_TYPE_QUICK  = 2;
+
     protected final Context mContext;
     private final View mIcon;
     private final View mDivider;
@@ -61,13 +65,15 @@
 
     private TextView mLabel;
     private QSDualTileLabel mDualLabel;
-    private boolean mDual;
+    private int mType;
     private OnClickListener mClickPrimary;
     private OnClickListener mClickSecondary;
     private OnLongClickListener mLongClick;
     private Drawable mTileBackground;
     private RippleDrawable mRipple;
 
+    private View mCircle;
+
     public QSTileView(Context context) {
         super(context);
 
@@ -89,6 +95,9 @@
         mIcon = createIcon();
         addView(mIcon);
 
+        mCircle = createCircleIcon();
+        addView(mCircle);
+
         mDivider = new View(mContext);
         mDivider.setBackgroundColor(context.getColor(R.color.qs_tile_divider));
         final int dh = res.getDimensionPixelSize(R.dimen.qs_tile_divider_height);
@@ -131,12 +140,12 @@
         }
         if (mDualLabel != null) {
             labelText = mDualLabel.getText();
-            labelDescription = mLabel.getContentDescription();
+            labelDescription = mLabel != null ? mLabel.getContentDescription() : null;
             removeView(mDualLabel);
             mDualLabel = null;
         }
         final Resources res = mContext.getResources();
-        if (mDual) {
+        if (mType == QS_TYPE_DUAL) {
             mDualLabel = new QSDualTileLabel(mContext);
             mDualLabel.setId(View.generateViewId());
             mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect);
@@ -157,7 +166,7 @@
             }
             addView(mDualLabel);
             mDualLabel.setAccessibilityTraversalAfter(mTopBackgroundView.getId());
-        } else {
+        } else if (mType == QS_TYPE_NORMAL) {
             mLabel = new TextView(mContext);
             mLabel.setTextColor(mContext.getColor(R.color.qs_tile_text));
             mLabel.setGravity(Gravity.CENTER_HORIZONTAL);
@@ -174,16 +183,16 @@
         }
     }
 
-    public boolean setDual(boolean dual) {
-        final boolean changed = dual != mDual;
-        mDual = dual;
+    public boolean setType(int type) {
+        final boolean changed = mType != type;
+        mType = type;
         if (changed) {
             recreateLabel();
         }
         if (mTileBackground instanceof RippleDrawable) {
             setRipple((RippleDrawable) mTileBackground);
         }
-        if (dual) {
+        if (mType == QS_TYPE_DUAL) {
             mTopBackgroundView.setOnClickListener(mClickPrimary);
             setOnClickListener(null);
             setClickable(false);
@@ -197,9 +206,10 @@
             setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
             setBackground(mTileBackground);
         }
-        mTopBackgroundView.setFocusable(dual);
-        setFocusable(!dual);
-        mDivider.setVisibility(dual ? VISIBLE : GONE);
+        mTopBackgroundView.setFocusable(mType == QS_TYPE_DUAL);
+        setFocusable(mType != QS_TYPE_DUAL);
+        mDivider.setVisibility(mType == QS_TYPE_DUAL ? VISIBLE : GONE);
+        mCircle.setVisibility(mType == QS_TYPE_QUICK ? VISIBLE : GONE);
         postInvalidate();
         return changed;
     }
@@ -225,6 +235,21 @@
         return icon;
     }
 
+    protected View createCircleIcon() {
+        final ImageView icon = new ImageView(mContext);
+        icon.setImageResource(R.drawable.ic_qs_circle);
+        // TODO: Not this.
+        icon.setPadding(20, 20, 20, 20);
+        return icon;
+    }
+
+    protected View createCircle() {
+        final ImageView icon = new ImageView(mContext);
+        icon.setId(android.R.id.icon);
+        icon.setScaleType(ScaleType.CENTER_INSIDE);
+        return icon;
+    }
+
     private Drawable newTileBackground() {
         final int[] attrs = new int[] { android.R.attr.selectableItemBackgroundBorderless };
         final TypedArray ta = mContext.obtainStyledAttributes(attrs);
@@ -234,7 +259,7 @@
     }
 
     private View labelView() {
-        return mDual ? mDualLabel : mLabel;
+        return mType == QS_TYPE_DUAL ? mDualLabel : mLabel;
     }
 
     @Override
@@ -243,9 +268,18 @@
         final int h = MeasureSpec.getSize(heightMeasureSpec);
         final int iconSpec = exactly(mIconSizePx);
         mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST), iconSpec);
-        labelView().measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
-        if (mDual) {
-            mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+        switch (mType) {
+            case QS_TYPE_QUICK:
+                mCircle.measure(
+                        MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY),
+                        MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY));
+                break;
+            case QS_TYPE_DUAL:
+                mDivider.measure(widthMeasureSpec, exactly(mDivider.getLayoutParams().height));
+            default:
+                labelView().measure(widthMeasureSpec,
+                        MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST));
+                break;
         }
         int heightSpec = exactly(
                 mIconSizePx + mTilePaddingBelowIconPx + mTilePaddingTopPx);
@@ -268,6 +302,10 @@
         top += mTileSpacingPx;
         top += mTilePaddingTopPx;
         final int iconLeft = (w - mIcon.getMeasuredWidth()) / 2;
+        if (mType == QS_TYPE_QUICK) {
+            top = (h - mIcon.getMeasuredHeight()) / 2;
+            layout(mCircle, 0, 0);
+        }
         layout(mIcon, iconLeft, top);
         if (mRipple != null) {
             updateRippleSize(w, h);
@@ -275,17 +313,19 @@
         }
         top = mIcon.getBottom();
         top += mTilePaddingBelowIconPx;
-        if (mDual) {
+        if (mType == QS_TYPE_DUAL) {
             layout(mDivider, 0, top);
             top = mDivider.getBottom();
         }
-        layout(labelView(), 0, top);
+        if (mType != QS_TYPE_QUICK) {
+            layout(labelView(), 0, top);
+        }
     }
 
     private void updateRippleSize(int width, int height) {
         // center the touch feedback on the center of the icon, and dial it down a bit
         final int cx = width / 2;
-        final int cy = mDual ? mIcon.getTop() + mIcon.getHeight() / 2 : height / 2;
+        final int cy = mType == QS_TYPE_DUAL ? mIcon.getTop() + mIcon.getHeight() / 2 : height / 2;
         final int rad = (int)(mIcon.getHeight() * 1.25f);
         mRipple.setHotspotBounds(cx - rad, cy - rad, cx + rad, cy + rad);
     }
@@ -298,11 +338,11 @@
         if (mIcon instanceof ImageView) {
             setIcon((ImageView) mIcon, state);
         }
-        if (mDual) {
+        if (mType == QS_TYPE_DUAL) {
             mDualLabel.setText(state.label);
             mDualLabel.setContentDescription(state.dualLabelContentDescription);
             mTopBackgroundView.setContentDescription(state.contentDescription);
-        } else {
+        } else if (mType == QS_TYPE_NORMAL) {
             mLabel.setText(state.label);
             setContentDescription(state.contentDescription);
         }
@@ -338,7 +378,7 @@
     public View updateAccessibilityOrder(View previousView) {
         View firstView;
         View lastView;
-        if (mDual) {
+        if (mType == QS_TYPE_DUAL) {
             lastView = mDualLabel;
             firstView = mTopBackgroundView;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/QuickTileLayout.java
new file mode 100644
index 0000000..bb2340c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickTileLayout.java
@@ -0,0 +1,28 @@
+package com.android.systemui.qs;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+public class QuickTileLayout extends LinearLayout {
+
+    public QuickTileLayout(Context context) {
+        this(context, null);
+    }
+
+    public QuickTileLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setGravity(Gravity.CENTER);
+    }
+
+    @Override
+    public void addView(View child, int index, ViewGroup.LayoutParams params) {
+        // Make everything square at the height of this view.
+        params = new LayoutParams(params.height, params.height);
+        ((LinearLayout.LayoutParams) params).weight = 1;
+        super.addView(child, index, params);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 02b8fe3..e0c39c5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -2,35 +2,63 @@
 
 import android.content.Context;
 import android.content.res.Resources;
+import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.QSPanel.TileRecord;
 
 import java.util.ArrayList;
 
-public class TileLayout extends ViewGroup {
+public class TileLayout extends ViewGroup implements QSTileLayout {
 
     private static final float TILE_ASPECT = 1.2f;
 
     private static final String TAG = "TileLayout";
 
     private int mDualTileUnderlap;
-    private int mColumns;
+    protected int mColumns;
     private int mCellWidth;
     private int mCellHeight;
     private int mLargeCellWidth;
     private int mLargeCellHeight;
 
-    private final ArrayList<TileRecord> mRecords;
+    protected boolean mAllowDual = true;
 
-    public TileLayout(Context context, ArrayList<TileRecord> records) {
-        super(context);
-        mRecords = records;
+    protected final ArrayList<TileRecord> mRecords = new ArrayList<>();
+
+    public TileLayout(Context context) {
+        this(context, null);
+    }
+
+    public TileLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
         updateResources();
     }
 
+    @Override
+    public int getOffsetTop(TileRecord tile) {
+        return getTop();
+    }
+
+    public void addTile(TileRecord tile) {
+        mRecords.add(tile);
+        addView(tile.tileView);
+    }
+
+    @Override
+    public void removeTile(TileRecord tile) {
+        mRecords.remove(tile);
+        removeView(tile.tileView);
+    }
+
+    @Override
+    public void setTileVisibility(TileRecord tile, int visibility) {
+        tile.tileView.setVisibility(visibility);
+    }
+
     public void updateResources() {
         final Resources res = mContext.getResources();
         final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns));
@@ -56,10 +84,11 @@
             if (record.tileView.getVisibility() == GONE) continue;
             // wrap to next column if we've reached the max # of columns
             // also don't allow dual + single tiles on the same row
-            if (r == -1 || c == (mColumns - 1) || rowIsDual != record.tile.supportsDualTargets()) {
+            if (r == -1 || c == (mColumns - 1)
+                    || rowIsDual != (mAllowDual && record.tile.supportsDualTargets())) {
                 r++;
                 c = 0;
-                rowIsDual = record.tile.supportsDualTargets();
+                rowIsDual = mAllowDual && record.tile.supportsDualTargets();
             } else {
                 c++;
             }
@@ -70,7 +99,8 @@
 
         View previousView = this;
         for (TileRecord record : mRecords) {
-            if (record.tileView.setDual(record.tile.supportsDualTargets())) {
+            if (record.tileView.setType(mAllowDual ? record.tile.getTileType()
+                    : QSTileView.QS_TYPE_NORMAL)) {
                 record.tileView.handleStateChanged(record.tile.getState());
             }
             if (record.tileView.getVisibility() == GONE) continue;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index abce31f..fd70d02 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -31,6 +31,7 @@
 import com.android.systemui.qs.QSDetailItems;
 import com.android.systemui.qs.QSDetailItems.Item;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
 import com.android.systemui.statusbar.policy.BluetoothController;
 
 import java.util.Collection;
@@ -43,15 +44,18 @@
     private final BluetoothController mController;
     private final BluetoothDetailAdapter mDetailAdapter;
 
-    public BluetoothTile(Host host) {
+    private final boolean mAlwaysDetail;
+
+    public BluetoothTile(Host host, boolean alwaysDetail) {
         super(host);
+        mAlwaysDetail = alwaysDetail;
         mController = host.getBluetoothController();
         mDetailAdapter = new BluetoothDetailAdapter();
     }
 
     @Override
-    public boolean supportsDualTargets() {
-        return true;
+    public int getTileType() {
+        return QSTileView.QS_TYPE_DUAL;
     }
 
     @Override
@@ -75,6 +79,10 @@
 
     @Override
     protected void handleClick() {
+        if (mAlwaysDetail) {
+            handleSecondaryClick();
+            return;
+        }
         final boolean isEnabled = (Boolean)mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
         mController.setBluetoothEnabled(!isEnabled);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java
new file mode 100644
index 0000000..13ccaaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QAirplaneTile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.systemui.qs.QSTileView;
+
+/** Quick settings tile: Wifi **/
+public class QAirplaneTile extends AirplaneModeTile {
+
+    public QAirplaneTile(Host host) {
+        super(host);
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java
new file mode 100644
index 0000000..02975cb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QBluetoothTile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.systemui.qs.QSTileView;
+
+/** Quick settings tile: Bluetooth **/
+public class QBluetoothTile extends BluetoothTile  {
+
+    public QBluetoothTile(Host host) {
+        super(host, false);
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java
new file mode 100644
index 0000000..31035cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QFlashlightTile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.systemui.qs.QSTileView;
+
+/** Quick settings tile: Wifi **/
+public class QFlashlightTile extends FlashlightTile {
+
+    public QFlashlightTile(Host host) {
+        super(host);
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java
new file mode 100644
index 0000000..e066bab
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QRotationLockTile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.systemui.qs.QSTileView;
+
+/** Quick settings tile: Rotation **/
+public class QRotationLockTile extends RotationLockTile {
+
+    public QRotationLockTile(Host host) {
+        super(host);
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
new file mode 100644
index 0000000..87194fb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QWifiTile.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.tiles;
+
+import com.android.systemui.qs.QSTileView;
+
+/** Quick settings tile: Wifi **/
+public class QWifiTile extends WifiTile {
+
+    public QWifiTile(Host host) {
+        super(host, false);
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index e654efd..3295e14 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -50,16 +50,19 @@
 
     private final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
 
-    public WifiTile(Host host) {
+    private final boolean mAlwaysDetail;
+
+    public WifiTile(Host host, boolean alwaysDetail) {
         super(host);
+        mAlwaysDetail = alwaysDetail;
         mController = host.getNetworkController();
         mWifiController = mController.getAccessPointController();
         mDetailAdapter = new WifiDetailAdapter();
     }
 
     @Override
-    public boolean supportsDualTargets() {
-        return true;
+    public int getTileType() {
+        return QSTileView.QS_TYPE_DUAL;
     }
 
     @Override
@@ -97,6 +100,10 @@
 
     @Override
     protected void handleClick() {
+        if (mAlwaysDetail) {
+            handleSecondaryClick();
+            return;
+        }
         mState.copyTo(mStateBeforeClick);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.enabled);
         mController.setWifiEnabled(!mState.enabled);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index b701e0b..300ea2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -197,6 +197,7 @@
                 break;
             case PLACE_FULL:
                 // Nothing to change.
+                mBounds[0] = null;
                 break;
         }
 
@@ -213,10 +214,13 @@
         dismiss();
         mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
 
-        // Resize all tasks beginning from the "oldest" one.
-        for (int i = additionalTasks; i >= 0; --i) {
-            if (mTasks[i] != null) {
-               mSsp.resizeTask(mTasks[i].key.id, mBounds[i]);
+        // In debug mode, we force all task to be resizeable regardless of the
+        // current app configuration.
+        if (RecentsConfiguration.getInstance().multiStackEnabled) {
+            for (int i = additionalTasks; i >= 0; --i) {
+                if (mTasks[i] != null) {
+                    mSsp.setTaskResizeable(mTasks[i].key.id);
+                }
             }
         }
 
@@ -224,7 +228,7 @@
         // the focus ends on the selected one.
         for (int i = additionalTasks; i >= 0; --i) {
             if (mTasks[i] != null) {
-                mRecentsView.launchTask(mTasks[i]);
+                mRecentsView.launchTask(mTasks[i], mBounds[i]);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 89aeabc..bead1b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -271,17 +271,12 @@
         return null;
     }
 
-    /** Resize a given task. */
-    public void resizeTask(int taskId, Rect bounds) {
+    /** Allow a task to resize. */
+    public void setTaskResizeable(int taskId) {
         if (mIam == null) return;
 
         try {
-            if (RecentsConfiguration.getInstance().multiStackEnabled) {
-                // In debug mode, we force all task to be resizeable regardless of the
-                // current app configuration.
-                mIam.setTaskResizeable(taskId, true);
-            }
-            mIam.resizeTask(taskId, bounds);
+            mIam.setTaskResizeable(taskId, true);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 00ac5f9..651b29a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -165,7 +165,7 @@
 
     /** Gets the next task in the stack - or if the last - the top task */
     public Task getNextTaskOrTopTask(Task taskToSearch) {
-        Task returnTask = null; 
+        Task returnTask = null;
         boolean found = false;
         List<TaskStackView> stackViews = getTaskStackViews();
         int stackCount = stackViews.size();
@@ -203,7 +203,7 @@
                 TaskView tv = taskViews.get(j);
                 Task task = tv.getTask();
                 if (tv.isFocusedTask()) {
-                    onTaskViewClicked(stackView, tv, stack, task, false);
+                    onTaskViewClicked(stackView, tv, stack, task, false, false, null);
                     return true;
                 }
             }
@@ -212,7 +212,7 @@
     }
 
     /** Launches a given task. */
-    public boolean launchTask(Task task) {
+    public boolean launchTask(Task task, Rect taskBounds) {
         // Get the first stack view
         List<TaskStackView> stackViews = getTaskStackViews();
         int stackCount = stackViews.size();
@@ -225,7 +225,7 @@
             for (int j = 0; j < taskViewCount; j++) {
                 TaskView tv = taskViews.get(j);
                 if (tv.getTask() == task) {
-                    onTaskViewClicked(stackView, tv, stack, task, false);
+                    onTaskViewClicked(stackView, tv, stack, task, false, true, taskBounds);
                     return true;
                 }
             }
@@ -250,7 +250,7 @@
                     if (tasks.get(j).isLaunchTarget) {
                         Task task = tasks.get(j);
                         TaskView tv = stackView.getChildViewForTask(task);
-                        onTaskViewClicked(stackView, tv, stack, task, false);
+                        onTaskViewClicked(stackView, tv, stack, task, false, false, null);
                         return true;
                     }
                 }
@@ -373,7 +373,7 @@
                     searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
         }
 
-        // Layout each TaskStackView with the full width and height of the window since the 
+        // Layout each TaskStackView with the full width and height of the window since the
         // transition view is a child of that stack view
         List<TaskStackView> stackViews = getTaskStackViews();
         int stackCount = stackViews.size();
@@ -604,7 +604,8 @@
 
     @Override
     public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
-                                  final TaskStack stack, final Task task, final boolean lockToTask) {
+                                  final TaskStack stack, final Task task, final boolean lockToTask,
+                                  final boolean boundsValid, final Rect bounds) {
 
         // Notify any callbacks of the launching of a new task
         if (mCb != null) {
@@ -632,9 +633,9 @@
         final SystemServicesProxy ssp =
                 RecentsTaskLoader.getInstance().getSystemServicesProxy();
         ActivityOptions opts = null;
+        ActivityOptions.OnAnimationStartedListener animStartedListener = null;
         if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
                 task.thumbnail.getHeight() > 0) {
-            ActivityOptions.OnAnimationStartedListener animStartedListener = null;
             if (lockToTask) {
                 animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
                     boolean mTriggered = false;
@@ -665,9 +666,14 @@
                         offsetX, offsetY, transform.rect.width(), transform.rect.height(),
                         sourceView.getHandler(), animStartedListener);
             }
+        } else {
+            opts = ActivityOptions.makeBasic();
         }
-
+        if (boundsValid) {
+            opts.setBounds(bounds);
+        }
         final ActivityOptions launchOpts = opts;
+        final boolean screenPinningRequested = (animStartedListener == null) && lockToTask;
         final Runnable launchRunnable = new Runnable() {
             @Override
             public void run() {
@@ -677,7 +683,7 @@
                 } else {
                     if (ssp.startActivityFromRecents(getContext(), task.key.id,
                             task.activityLabel, launchOpts)) {
-                        if (launchOpts == null && lockToTask) {
+                        if (screenPinningRequested) {
                             mCb.onScreenPinningRequest();
                         }
                     } else {
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 0068f84..4e82c8a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -59,7 +59,7 @@
     /** The TaskView callbacks */
     interface TaskStackViewCallbacks {
         public void onTaskViewClicked(TaskStackView stackView, TaskView tv, TaskStack stack, Task t,
-                                      boolean lockToTask);
+                                      boolean lockToTask, boolean boundsValid, Rect bounds);
         public void onTaskViewAppInfoClicked(Task t);
         public void onTaskViewDismissed(Task t);
         public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks);
@@ -1377,7 +1377,7 @@
         mUIDozeTrigger.stopDozing();
 
         if (mCb != null) {
-            mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask);
+            mCb.onTaskViewClicked(this, tv, mStack, task, lockToTask, false, null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index de6c4b1..2c964be 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1754,11 +1754,13 @@
     protected void handleVisibleToUserChanged(boolean visibleToUser) {
         try {
             if (visibleToUser) {
-                boolean clearNotificationEffects = !isPanelFullyCollapsed() &&
-                    (mShowLockscreenNotifications ||
-                        (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED));
+                boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
+                boolean clearNotificationEffects =
+                    ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
+                            (!pinnedHeadsUp && (mState == StatusBarState.SHADE
+                                    || mState == StatusBarState.SHADE_LOCKED)));
                 int notificationLoad = mNotificationData.getActiveNotifications().size();
-                if (mHeadsUpManager.hasPinnedHeadsUp() && isPanelFullyCollapsed())  {
+                if (pinnedHeadsUp && isPanelFullyCollapsed())  {
                     notificationLoad = 1;
                 } else {
                     MetricsLogger.histogram(mContext, "note_load", notificationLoad);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.java
new file mode 100644
index 0000000..2c6987c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppButtonData.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 com.android.systemui.statusbar.phone;
+
+import android.app.ActivityManager.RecentTaskInfo;
+
+import java.util.ArrayList;
+
+/**
+ * Data associated with an app button.
+ */
+class AppButtonData {
+    public final AppInfo appInfo;
+    public boolean pinned;
+    // Recent tasks for this app, sorted by lastActiveTime, descending.
+    public ArrayList<RecentTaskInfo> tasks;
+
+    public AppButtonData(AppInfo appInfo, boolean pinned) {
+        this.appInfo = appInfo;
+        this.pinned = pinned;
+    }
+
+    /**
+     * Returns true if the button contains no useful information and should be removed.
+     */
+    public boolean isEmpty() {
+        return !pinned && (tasks == null || tasks.isEmpty());
+    }
+
+    public void addTask(RecentTaskInfo task) {
+        if (tasks == null) {
+            tasks = new ArrayList<RecentTaskInfo>();
+        }
+        tasks.add(task);
+    }
+
+    public void clearTasks() {
+        if (tasks != null) {
+            tasks.clear();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
index e34c821..8f0b532 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
@@ -39,4 +39,16 @@
     public UserHandle getUser() {
         return mUser;
     }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final AppInfo other = (AppInfo) obj;
+        return mComponentName.equals(other.mComponentName) && mUser.equals(other.mUser);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
index 4e69999..84082db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -227,7 +227,7 @@
                 return MODE_DISMISS_BOUNCER;
             } else if (unlockingAllowed) {
                 return MODE_UNLOCK;
-            } else {
+            } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 return MODE_SHOW_BOUNCER;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
index f46d1a6..d2bec7c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
@@ -20,6 +20,12 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
 import android.os.RemoteException;
@@ -30,7 +36,7 @@
  * Retrieves the icon for an activity and sets it as the Drawable on an ImageView. The ImageView
  * is hidden if the activity isn't recognized or if there is no icon.
  */
-class GetActivityIconTask extends AsyncTask<AppInfo, Void, Drawable> {
+class GetActivityIconTask extends AsyncTask<AppButtonData, Void, Drawable> {
     private final static String TAG = "GetActivityIconTask";
 
     private final PackageManager mPackageManager;
@@ -44,11 +50,12 @@
     }
 
     @Override
-    protected Drawable doInBackground(AppInfo... params) {
+    protected Drawable doInBackground(AppButtonData... params) {
         if (params.length != 1) {
             throw new IllegalArgumentException("Expected one parameter");
         }
-        AppInfo appInfo = params[0];
+        AppButtonData buttonData = params[0];
+        AppInfo appInfo = buttonData.appInfo;
         try {
             IPackageManager mPM = AppGlobals.getPackageManager();
             ActivityInfo ai = mPM.getActivityInfo(
@@ -62,7 +69,37 @@
             }
 
             Drawable unbadgedIcon = ai.loadIcon(mPackageManager);
-            return mPackageManager.getUserBadgedIcon(unbadgedIcon, appInfo.getUser());
+            Drawable badgedIcon =
+                    mPackageManager.getUserBadgedIcon(unbadgedIcon, appInfo.getUser());
+
+            if (NavigationBarApps.DEBUG) {
+                // Draw pinned indicator and number of running tasks.
+                Bitmap bitmap = Bitmap.createBitmap(
+                        badgedIcon.getIntrinsicWidth(),
+                        badgedIcon.getIntrinsicHeight(),
+                        Bitmap.Config.ARGB_8888);
+                Canvas canvas = new Canvas(bitmap);
+                badgedIcon.setBounds(
+                        0, 0, badgedIcon.getIntrinsicWidth(), badgedIcon.getIntrinsicHeight());
+                badgedIcon.draw(canvas);
+                Paint paint = new Paint();
+                paint.setStyle(Paint.Style.FILL);
+                if (buttonData.pinned) {
+                    paint.setColor(Color.WHITE);
+                    canvas.drawCircle(10, 10, 10, paint);
+                }
+                if (buttonData.tasks != null && buttonData.tasks.size() > 0) {
+                    paint.setColor(Color.BLACK);
+                    canvas.drawCircle(60, 30, 30, paint);
+                    paint.setColor(Color.WHITE);
+                    paint.setTextSize(50);
+                    paint.setTypeface(Typeface.create("sans-serif", Typeface.BOLD));
+                    canvas.drawText(Integer.toString(buttonData.tasks.size()), 50, 50, paint);
+                }
+                badgedIcon = new BitmapDrawable(null, bitmap);
+            }
+
+            return  badgedIcon;
         } catch (RemoteException e) {
             Slog.w(TAG, "Icon not found for " + appInfo, e);
             return null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d30411a..f4439bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -262,14 +262,21 @@
         return (secure && !canSkipBouncer) ? SECURE_CAMERA_INTENT : INSECURE_CAMERA_INTENT;
     }
 
+    /**
+     * Resolves the intent to launch the camera application.
+     */
+    public ResolveInfo resolveCameraIntent() {
+        return mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
+                PackageManager.MATCH_DEFAULT_ONLY,
+                KeyguardUpdateMonitor.getCurrentUser());
+    }
+
     private void updateCameraVisibility() {
         if (mCameraImageView == null) {
             // Things are not set up yet; reply hazy, ask again later
             return;
         }
-        ResolveInfo resolved = mContext.getPackageManager().resolveActivityAsUser(getCameraIntent(),
-                PackageManager.MATCH_DEFAULT_ONLY,
-                KeyguardUpdateMonitor.getCurrentUser());
+        ResolveInfo resolved = resolveCameraIntent();
         boolean visible = !isCameraDisabledByDpm() && resolved != null
                 && getResources().getBoolean(R.bool.config_keyguardShowCameraAffordance)
                 && mUserSetupComplete;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 463abfc..030501b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -100,6 +100,8 @@
         // TODO: Real icon for facelock.
         int state = getState();
         boolean anyFingerprintIcon = state == STATE_FINGERPRINT || state == STATE_FINGERPRINT_ERROR;
+        boolean useAdditionalPadding = anyFingerprintIcon;
+        boolean trustHidden = anyFingerprintIcon;
         if (state != mLastState || mDeviceInteractive != mLastDeviceInteractive
                 || mScreenOn != mLastScreenOn) {
             boolean isAnim = true;
@@ -107,6 +109,16 @@
                     mDeviceInteractive, mLastScreenOn, mScreenOn);
             if (iconRes == R.drawable.lockscreen_fingerprint_draw_off_animation) {
                 anyFingerprintIcon = true;
+                useAdditionalPadding = true;
+                trustHidden = true;
+            } else if (iconRes == R.drawable.trusted_state_to_error_animation) {
+                anyFingerprintIcon = true;
+                useAdditionalPadding = false;
+                trustHidden = true;
+            } else if (iconRes == R.drawable.error_to_trustedstate_animation) {
+                anyFingerprintIcon = true;
+                useAdditionalPadding = false;
+                trustHidden = false;
             }
             if (iconRes == -1) {
                 iconRes = getIconForState(state, mScreenOn, mDeviceInteractive);
@@ -124,7 +136,7 @@
                     || icon.getIntrinsicWidth() != iconWidth)) {
                 icon = new IntrinsicSizeDrawable(icon, iconWidth, iconHeight);
             }
-            setPaddingRelative(0, 0, 0, anyFingerprintIcon
+            setPaddingRelative(0, 0, 0, useAdditionalPadding
                     ? getResources().getDimensionPixelSize(
                     R.dimen.fingerprint_icon_additional_padding)
                     : 0);
@@ -145,7 +157,7 @@
         }
 
         // Hide trust circle when fingerprint is running.
-        boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !anyFingerprintIcon;
+        boolean trustManaged = mUnlockMethodCache.isTrustManaged() && !trustHidden;
         mTrustDrawable.setTrustManaged(trustManaged);
         updateClickability();
     }
@@ -154,10 +166,13 @@
         if (mAccessibilityController == null) {
             return;
         }
+        boolean trustManagedOrFingerprintAllowed = mUnlockMethodCache.isTrustManaged()
+                || KeyguardUpdateMonitor.getInstance(mContext).isUnlockingWithFingerprintAllowed();
+
         boolean clickToUnlock = mAccessibilityController.isTouchExplorationEnabled();
-        boolean clickToForceLock = mUnlockMethodCache.isTrustManaged()
+        boolean clickToForceLock = trustManagedOrFingerprintAllowed
                 && !mAccessibilityController.isAccessibilityEnabled();
-        boolean longClickToForceLock = mUnlockMethodCache.isTrustManaged()
+        boolean longClickToForceLock = trustManagedOrFingerprintAllowed
                 && !clickToForceLock;
         setClickable(clickToForceLock || clickToUnlock);
         setLongClickable(longClickToForceLock);
@@ -208,6 +223,10 @@
             boolean oldScreenOn, boolean screenOn) {
         if (oldState == STATE_FINGERPRINT && newState == STATE_FINGERPRINT_ERROR) {
             return R.drawable.lockscreen_fingerprint_fp_to_error_state_animation;
+        } else if (oldState == STATE_LOCK_OPEN && newState == STATE_FINGERPRINT_ERROR) {
+            return R.drawable.trusted_state_to_error_animation;
+        } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_LOCK_OPEN) {
+            return R.drawable.error_to_trustedstate_animation;
         } else if (oldState == STATE_FINGERPRINT_ERROR && newState == STATE_FINGERPRINT) {
             return R.drawable.lockscreen_fingerprint_error_state_to_fp_animation;
         } else if (oldState == STATE_FINGERPRINT && newState == STATE_LOCK_OPEN
@@ -225,14 +244,14 @@
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         boolean fingerprintRunning = updateMonitor.isFingerprintDetectionRunning();
         boolean unlockingAllowed = updateMonitor.isUnlockingWithFingerprintAllowed();
-        if (mUnlockMethodCache.canSkipBouncer()) {
-            return STATE_LOCK_OPEN;
-        } else if (mTransientFpError) {
+        if (mTransientFpError) {
             return STATE_FINGERPRINT_ERROR;
-        } else if (fingerprintRunning && unlockingAllowed) {
-            return STATE_FINGERPRINT;
+        } else if (mUnlockMethodCache.canSkipBouncer()) {
+            return STATE_LOCK_OPEN;
         } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
             return STATE_FACE_UNLOCK;
+        } else if (fingerprintRunning && unlockingAllowed) {
+            return STATE_FINGERPRINT;
         } else {
             return STATE_LOCKED;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index adcec98..1c9b04f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -19,7 +19,11 @@
 import android.animation.LayoutTransition;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
+import android.app.IActivityManager;
+import android.app.ITaskStackListener;
 import android.content.BroadcastReceiver;
 import android.content.ClipData;
 import android.content.ClipDescription;
@@ -29,8 +33,10 @@
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AttributeSet;
@@ -46,14 +52,17 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.systemui.R;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Container for application icons that appear in the navigation bar. Their appearance is similar
- * to the launcher hotseat. Clicking an icon launches the associated activity. A long click will
- * trigger a drag to allow the icons to be reordered. As an icon is dragged the other icons shift
- * to make space for it to be dropped. These layout changes are animated.
+ * to the launcher hotseat. Clicking an icon launches or activates the associated activity. A long
+ * click will trigger a drag to allow the icons to be reordered. As an icon is dragged the other
+ * icons shift to make space for it to be dropped. These layout changes are animated.
  */
 class NavigationBarApps extends LinearLayout {
-    private final static boolean DEBUG = false;
+    public final static boolean DEBUG = false;
     private final static String TAG = "NavigationBarApps";
 
     /**
@@ -73,12 +82,12 @@
 
     // This view has two roles:
     // 1) If the drag started outside the pinned apps list, it is a placeholder icon with a null
-    // data model entry.
+    // tag.
     // 2) If the drag started inside the pinned apps list, it is the icon for the app being dragged
-    // with the associated data model entry.
+    // with the associated AppInfo tag.
     // The icon is set invisible for the duration of the drag, creating a visual space for a drop.
     // When the user is not dragging this member is null.
-    private View mDragView;
+    private ImageView mDragView;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -96,9 +105,7 @@
 
     public NavigationBarApps(Context context, AttributeSet attrs) {
         super(context, attrs);
-        if (sAppsModel == null) {
-            sAppsModel = new NavigationBarAppsModel(context);
-        }
+        sAppsModel = new NavigationBarAppsModel(context);
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mLayoutInflater = LayoutInflater.from(context);
@@ -116,19 +123,27 @@
         transition.setStartDelay(LayoutTransition.CHANGE_DISAPPEARING, 0);
         transition.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 0);
         setLayoutTransition(transition);
+
+        TaskStackListener taskStackListener = new TaskStackListener();
+        IActivityManager iam = ActivityManagerNative.getDefault();
+        try {
+            iam.registerTaskStackListener(taskStackListener);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "registerTaskStackListener failed", e);
+        }
     }
 
     // Monitor that catches events like "app uninstalled".
     private class AppPackageMonitor extends PackageMonitor {
         @Override
         public void onPackageRemoved(String packageName, int uid) {
-            postRemoveIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
+            postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
             super.onPackageRemoved(packageName, uid);
         }
 
         @Override
         public void onPackageModified(String packageName) {
-            postRemoveIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
+            postUnpinIfUnlauncheable(packageName, new UserHandle(getChangingUserId()));
             super.onPackageModified(packageName);
         }
 
@@ -138,7 +153,7 @@
                 UserHandle user = new UserHandle(getChangingUserId());
 
                 for (String packageName : packages) {
-                    postRemoveIfUnlauncheable(packageName, user);
+                    postUnpinIfUnlauncheable(packageName, user);
                 }
             }
             super.onPackagesAvailable(packages);
@@ -150,29 +165,36 @@
                 UserHandle user = new UserHandle(getChangingUserId());
 
                 for (String packageName : packages) {
-                    postRemoveIfUnlauncheable(packageName, user);
+                    postUnpinIfUnlauncheable(packageName, user);
                 }
             }
             super.onPackagesUnavailable(packages);
         }
     }
 
-    private void postRemoveIfUnlauncheable(final String packageName, final UserHandle user) {
+    private void postUnpinIfUnlauncheable(final String packageName, final UserHandle user) {
         // This method doesn't necessarily get called in the main thread. Redirect the call into
         // the main thread.
         post(new Runnable() {
             @Override
             public void run() {
                 if (!isAttachedToWindow()) return;
-                removeIfUnlauncheable(packageName, user);
+                unpinIfUnlauncheable(packageName, user);
             }
         });
     }
 
-    private void removeIfUnlauncheable(String packageName, UserHandle user) {
-        // Remove icons for all apps that match a package that perhaps became unlauncheable.
-        for(int i = sAppsModel.getAppCount() - 1; i >= 0; --i) {
-            AppInfo appInfo = sAppsModel.getApp(i);
+    private void unpinIfUnlauncheable(String packageName, UserHandle user) {
+        // Unpin icons for all apps that match a package that perhaps became unlauncheable.
+        boolean appsWereUnpinned = false;
+        for(int i = getChildCount() - 1; i >= 0; --i) {
+            View child = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)child.getTag();
+            if (appButtonData == null) continue;  // Skip the drag placeholder.
+
+            if (!appButtonData.pinned) continue;
+
+            AppInfo appInfo = appButtonData.appInfo;
             if (!appInfo.getUser().equals(user)) continue;
 
             ComponentName appComponentName = appInfo.getComponentName();
@@ -182,9 +204,15 @@
                 continue;
             }
 
-            removeViewAt(i);
-            sAppsModel.removeApp(i);
-            sAppsModel.savePrefs();
+            appButtonData.pinned = false;
+            appsWereUnpinned = true;
+
+            if (appButtonData.isEmpty()) {
+                removeViewAt(i);
+            }
+        }
+        if (appsWereUnpinned) {
+            savePinnedApps();
         }
     }
 
@@ -204,7 +232,8 @@
         parent.setLayoutTransition(transition);
 
         sAppsModel.setCurrentUser(ActivityManager.getCurrentUser());
-        recreateAppButtons();
+        recreatePinnedAppButtons();
+        updateRecentApps();
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -221,50 +250,70 @@
         mAppPackageMonitor.unregister();
     }
 
+    private void addAppButton(AppButtonData appButtonData) {
+        ImageView button = createAppButton(appButtonData);
+        addView(button);
+
+        AppInfo app = appButtonData.appInfo;
+        CharSequence appLabel = getAppLabel(mPackageManager, app.getComponentName());
+        button.setContentDescription(appLabel);
+
+        // Load the icon asynchronously.
+        new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
+    }
+
     /**
      * Creates an ImageView icon for each pinned app. Removes any existing icons. May be called
      * to synchronize the current view with the shared data mode.
      */
-    public void recreateAppButtons() {
+    private void recreatePinnedAppButtons() {
         // Remove any existing icon buttons.
         removeAllViews();
 
-        int appCount = sAppsModel.getAppCount();
+        List<AppInfo> apps = sAppsModel.getApps();
+        int appCount = apps.size();
         for (int i = 0; i < appCount; i++) {
-            ImageView button = createAppButton();
-            addView(button);
-
-            AppInfo app = sAppsModel.getApp(i);
-            CharSequence appLabel = getAppLabel(mPackageManager, app.getComponentName());
-            button.setContentDescription(appLabel);
-
-            // Load the icon asynchronously.
-            new GetActivityIconTask(mPackageManager, button).execute(app);
+            AppInfo app = apps.get(i);
+            addAppButton(new AppButtonData(app, true /* pinned */));
         }
     }
 
     /**
-     * Creates a new ImageView for a launcher activity, inflated from
-     * R.layout.navigation_bar_app_item.
+     * Saves pinned apps stored in app icons into the data model.
      */
-    private ImageView createAppButton() {
+    private void savePinnedApps() {
+        List<AppInfo> apps = new ArrayList<AppInfo>();
+        int childCount = getChildCount();
+        for (int i = 0; i != childCount; ++i) {
+            View child = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)child.getTag();
+            if (appButtonData == null) continue;  // Skip the drag placeholder.
+            if(!appButtonData.pinned) continue;
+            apps.add(appButtonData.appInfo);
+        }
+        sAppsModel.setApps(apps);
+    }
+
+    /**
+     * Creates a new ImageView for an app, inflated from R.layout.navigation_bar_app_item.
+     */
+    private ImageView createAppButton(AppButtonData appButtonData) {
         ImageView button = (ImageView) mLayoutInflater.inflate(
                 R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
         button.setOnClickListener(new AppClickListener());
         // TODO: Ripple effect. Use either KeyButtonRipple or the default ripple background.
         button.setOnLongClickListener(new AppLongClickListener());
         button.setOnDragListener(new AppIconDragListener());
+        button.setTag(appButtonData);
         return button;
     }
 
-    // Not shared with NavigationBarRecents because the data model is specific to pinned apps.
     private class AppLongClickListener implements View.OnLongClickListener {
         @Override
         public boolean onLongClick(View v) {
-            mDragView = v;
-            ImageView icon = (ImageView) v;
-            AppInfo app = sAppsModel.getApp(indexOfChild(v));
-            startAppDrag(icon, app);
+            mDragView = (ImageView) v;
+            AppButtonData appButtonData = (AppButtonData) v.getTag();
+            startAppDrag(mDragView, appButtonData.appInfo);
             return true;
         }
     }
@@ -368,13 +417,11 @@
     }
 
     /**
-     * Creates a blank icon-sized View to create an empty space during a drag. Also creates a data
-     * model entry so the rest of the code can assume it is reordering existing entries.
+     * Creates a blank icon-sized View to create an empty space during a drag.
      */
     private ImageView createPlaceholderDragView(int index) {
-        ImageView button = createAppButton();
+        ImageView button = createAppButton(null);
         addView(button, index);
-        sAppsModel.addApp(index, null /* name */);
         return button;
     }
 
@@ -399,7 +446,6 @@
         }
 
         // "Move" the dragged app by removing it and adding it back at the target location.
-        int dragViewIndex = indexOfChild(mDragView);
         int targetIndex = indexOfChild(target);
         // This works, but is subtle:
         // * If dragViewIndex > targetIndex then the dragged app is moving from right to left and
@@ -409,10 +455,6 @@
         //   the view at targetIndex will therefore place the app *after* the target.
         removeView(mDragView);
         addView(mDragView, targetIndex);
-
-        // Update the data model.
-        AppInfo app = sAppsModel.removeApp(dragViewIndex);
-        sAppsModel.addApp(targetIndex, app);
     }
 
     private boolean onDrop(DragEvent event) {
@@ -423,32 +465,30 @@
             return true;
         }
 
-        // If this was an existing app being dragged then end the drag.
-        int dragViewIndex = indexOfChild(mDragView);
-        if (sAppsModel.getApp(dragViewIndex) != null) {
-            endDrag();
-            return true;
-        }
-
-        // The drag view was a placeholder. Unpack the drop.
+        boolean dragResult = true;
         AppInfo appInfo = getAppFromDragEvent(event);
         if (appInfo == null) {
-            // This wasn't a valid drop. Clean up the placeholder and model.
+            // This wasn't a valid drop. Clean up the placeholder.
             removePlaceholderDragViewIfNeeded();
-            return false;
+            dragResult = false;
+        } else if (mDragView.getTag() == null) {
+            // This is a drag that adds a new app. Convert the placeholder to a real icon.
+            updateApp(mDragView, new AppButtonData(appInfo, true /* pinned */));
         }
-
-        // The drop had valid data. Update the placeholder with a real activity and icon.
-        updateAppAt(dragViewIndex, appInfo);
         endDrag();
-        return true;
+        return dragResult;
     }
 
     /** Cleans up at the end of a drag. */
     private void endDrag() {
+        // An earlier drag event might have canceled the drag. If so, there is nothing to do.
+        if (mDragView == null) return;
+
         mDragView.setVisibility(View.VISIBLE);
         mDragView = null;
-        sAppsModel.savePrefs();
+        savePinnedApps();
+        // Add recent tasks to the info of the potentially added app.
+        updateRecentApps();
     }
 
     /** Returns an app info from a DragEvent, or null if the data wasn't valid. */
@@ -488,22 +528,18 @@
     }
 
     /** Updates the app at a given view index. */
-    private void updateAppAt(int index, AppInfo appInfo) {
-        sAppsModel.setApp(index, appInfo);
-        ImageView button = (ImageView) getChildAt(index);
-        new GetActivityIconTask(mPackageManager, button).execute(appInfo);
+    private void updateApp(ImageView button, AppButtonData appButtonData) {
+        button.setTag(appButtonData);
+        new GetActivityIconTask(mPackageManager, button).execute(appButtonData);
     }
 
-    /** Removes the empty placeholder view and cleans up the data model. */
+    /** Removes the empty placeholder view. */
     private void removePlaceholderDragViewIfNeeded() {
         // If the drag has ended already there is nothing to do.
         if (mDragView == null) {
             return;
         }
-        int index = indexOfChild(mDragView);
-        removeViewAt(index);
-        sAppsModel.removeApp(index);
-        endDrag();
+        removeView(mDragView);
     }
 
     /** Cleans up at the end of the drag. */
@@ -511,6 +547,7 @@
         if (DEBUG) Slog.d(TAG, "onDragEnded");
         // If the icon wasn't already dropped into the app list then remove the placeholder.
         removePlaceholderDragViewIfNeeded();
+        endDrag();
         return true;
     }
 
@@ -546,9 +583,7 @@
      * A click listener that launches an activity.
      */
     private class AppClickListener implements View.OnClickListener {
-        @Override
-        public void onClick(View v) {
-            AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
+        private void launchApp(AppInfo appInfo, View anchor) {
             Intent launchIntent = sAppsModel.buildAppLaunchIntent(appInfo);
             if (launchIntent == null) {
                 Toast.makeText(
@@ -561,31 +596,226 @@
             // already open in a visible window. In that case we should move the task to front
             // with minimal animation, perhaps using ActivityManager.moveTaskToFront().
             Rect sourceBounds = new Rect();
-            v.getBoundsOnScreen(sourceBounds);
+            anchor.getBoundsOnScreen(sourceBounds);
             ActivityOptions opts =
-                    ActivityOptions.makeScaleUpAnimation(v, 0, 0, v.getWidth(), v.getHeight());
+                    ActivityOptions.makeScaleUpAnimation(
+                            anchor, 0, 0, anchor.getWidth(), anchor.getHeight());
             Bundle optsBundle = opts.toBundle();
             launchIntent.setSourceBounds(sourceBounds);
 
             mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
         }
+
+        private void activateLatestTask(List<RecentTaskInfo> tasks) {
+            // 'tasks' is guaranteed to be non-empty.
+            int latestTaskPersistentId = tasks.get(0).persistentId;
+            // Launch or bring the activity to front.
+            IActivityManager manager = ActivityManagerNative.getDefault();
+            try {
+                manager.startActivityFromRecents(latestTaskPersistentId, null /* options */);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception when activating a recent task", e);
+            } catch (IllegalArgumentException e) {
+                Slog.e(TAG, "Exception when activating a recent task", e);
+            }
+        }
+
+        @Override
+        public void onClick(View v) {
+            AppButtonData appButtonData = (AppButtonData)v.getTag();
+
+            if (appButtonData.tasks == null || appButtonData.tasks.size() == 0) {
+                launchApp(appButtonData.appInfo, v);
+            } else {
+                activateLatestTask(appButtonData.tasks);
+            }
+        }
     }
 
     private void onUserSwitched(int currentUserId) {
         sAppsModel.setCurrentUser(currentUserId);
-        recreateAppButtons();
+        recreatePinnedAppButtons();
     }
 
     private void onManagedProfileRemoved(UserHandle removedProfile) {
-        boolean removedApps = false;
-        for(int i = sAppsModel.getAppCount() - 1; i >= 0; --i) {
-            AppInfo appInfo = sAppsModel.getApp(i);
-            if (!appInfo.getUser().equals(removedProfile)) continue;
+        // Unpin apps from the removed profile.
+        boolean itemsWereUnpinned = false;
+        for(int i = getChildCount() - 1; i >= 0; --i) {
+            View view = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)view.getTag();
+            if (appButtonData == null) return;  // Skip the drag placeholder.
+            if (!appButtonData.pinned) continue;
+            if (!appButtonData.appInfo.getUser().equals(removedProfile)) continue;
 
-            removeViewAt(i);
-            sAppsModel.removeApp(i);
-            removedApps = true;
+            appButtonData.pinned = false;
+            itemsWereUnpinned = true;
+            if (appButtonData.isEmpty()) {
+                removeViewAt(i);
+            }
         }
-        if (removedApps) sAppsModel.savePrefs();
+        if (itemsWereUnpinned) {
+            savePinnedApps();
+        }
+    }
+
+    /**
+     * Returns app data for a button that matches the provided app info, if it exists, or null
+     * otherwise.
+     */
+    private AppButtonData findAppButtonData(AppInfo appInfo) {
+        int size = getChildCount();
+        for (int i = 0; i < size; ++i) {
+            View view = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)view.getTag();
+            if (appButtonData == null) continue;  // Skip the drag placeholder.
+            if (appButtonData.appInfo.equals(appInfo)) {
+                return appButtonData;
+            }
+        }
+        return null;
+    }
+
+    private void updateTasks(List<RecentTaskInfo> tasks) {
+        // Remove tasks from all app buttons.
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            View view = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)view.getTag();
+            if (appButtonData == null) return;  // Skip the drag placeholder.
+            appButtonData.clearTasks();
+        }
+
+        // Re-add tasks to app buttons, adding new buttons if needed.
+        int size = tasks.size();
+        for (int i = 0; i != size; ++i) {
+            RecentTaskInfo task = tasks.get(i);
+            AppInfo taskAppInfo = taskToAppInfo(task);
+            if (taskAppInfo == null) continue;
+            AppButtonData appButtonData = findAppButtonData(taskAppInfo);
+            if (appButtonData == null) {
+                appButtonData = new AppButtonData(taskAppInfo, false);
+                addAppButton(appButtonData);
+            }
+            appButtonData.addTask(task);
+        }
+
+        // Remove unpinned apps that now have no tasks.
+        for (int i = getChildCount() - 1; i >= 0; --i) {
+            View view = getChildAt(i);
+            AppButtonData appButtonData = (AppButtonData)view.getTag();
+            if (appButtonData == null) return;  // Skip the drag placeholder.
+            if (appButtonData.isEmpty()) {
+                removeViewAt(i);
+            }
+        }
+
+        if (DEBUG) {
+            for (int i = getChildCount() - 1; i >= 0; --i) {
+                View view = getChildAt(i);
+                AppButtonData appButtonData = (AppButtonData)view.getTag();
+                if (appButtonData == null) return;  // Skip the drag placeholder.
+                new GetActivityIconTask(mPackageManager, (ImageView )view).execute(appButtonData);
+
+            }
+        }
+    }
+
+    private void updateRecentApps() {
+        ActivityManager activityManager =
+                (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+        // TODO: Should this be getRunningTasks?
+        List<RecentTaskInfo> recentTasks = activityManager.getRecentTasksForUser(
+                ActivityManager.getMaxAppRecentsLimitStatic(),
+                ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
+                        ActivityManager.RECENT_IGNORE_UNAVAILABLE |
+                        ActivityManager.RECENT_INCLUDE_PROFILES,
+                UserHandle.USER_CURRENT);
+        if (DEBUG) Slog.d(TAG, "Got recents " + recentTasks.size());
+        updateTasks(recentTasks);
+    }
+
+    private static ComponentName getActivityForTask(RecentTaskInfo task) {
+        // If the task was started from an alias, return the actual activity component that was
+        // initially started.
+        if (task.origActivity != null) {
+            return task.origActivity;
+        }
+        // Prefer the first activity of the task.
+        if (task.baseActivity != null) {
+            return task.baseActivity;
+        }
+        // Then goes the activity that started the task.
+        if (task.realActivity != null) {
+            return task.realActivity;
+        }
+        // This should not happen, but fall back to the base intent's activity component name.
+        return task.baseIntent.getComponent();
+    }
+
+    private ComponentName getLaunchComponentForPackage(String packageName, int userId) {
+        // This code is based on ApplicationPackageManager.getLaunchIntentForPackage.
+        PackageManager packageManager = mContext.getPackageManager();
+
+        // First see if the package has an INFO activity; the existence of
+        // such an activity is implied to be the desired front-door for the
+        // overall package (such as if it has multiple launcher entries).
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(Intent.CATEGORY_INFO);
+        intentToResolve.setPackage(packageName);
+        List<ResolveInfo> ris = packageManager.queryIntentActivitiesAsUser(
+                intentToResolve, 0, userId);
+
+        // Otherwise, try to find a main launcher activity.
+        if (ris == null || ris.size() <= 0) {
+            // reuse the intent instance
+            intentToResolve.removeCategory(Intent.CATEGORY_INFO);
+            intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
+            intentToResolve.setPackage(packageName);
+            ris = packageManager.queryIntentActivitiesAsUser(intentToResolve, 0, userId);
+        }
+        if (ris == null || ris.size() <= 0) {
+            Slog.e(TAG, "Failed to build intent for " + packageName);
+            return null;
+        }
+        return new ComponentName(ris.get(0).activityInfo.packageName,
+                ris.get(0).activityInfo.name);
+    }
+
+    private AppInfo taskToAppInfo(RecentTaskInfo task) {
+        ComponentName componentName = getActivityForTask(task);
+        UserHandle taskUser = new UserHandle(task.userId);
+        AppInfo appInfo = new AppInfo(componentName, taskUser);
+
+        if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
+            // If task's activity is not launcheable, fall back to a launch component of the
+            // task's package.
+            ComponentName component = getLaunchComponentForPackage(
+                    componentName.getPackageName(), task.userId);
+
+            if (component == null) {
+                return null;
+            }
+
+            appInfo = new AppInfo(component, taskUser);
+        }
+
+        return appInfo;
+    }
+
+    /**
+     * A listener that updates the app buttons whenever the recents task stack changes.
+     */
+    private class TaskStackListener extends ITaskStackListener.Stub {
+        @Override
+        public void onTaskStackChanged() throws RemoteException {
+            // Post the message back to the UI thread.
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    if (isAttachedToWindow()) {
+                        updateRecentApps();
+                    }
+                }
+            });
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
index c7b9e1c..832a3e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarAppsModel.java
@@ -28,7 +28,6 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.util.Log;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -78,7 +77,7 @@
     private final SharedPreferences mPrefs;
 
     // Apps are represented as an ordered list of app infos.
-    private final List<AppInfo> mApps = new ArrayList<AppInfo>();
+    private List<AppInfo> mApps = new ArrayList<AppInfo>();
 
     // Id of the current user.
     private int mCurrentUserId = -1;
@@ -119,7 +118,7 @@
                     || appUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
                     || appUserInfo.profileGroupId != currentUserInfo.profileGroupId
                     || !appUserInfo.isEnabled()) {
-                Log.e(TAG, "User " + appUserId +
+                Slog.e(TAG, "User " + appUserId +
                         " is is not a profile of the current user, or is disabled.");
                 return null;
             }
@@ -134,16 +133,16 @@
         try {
             ActivityInfo info = getPackageManager().getActivityInfo(component, 0, appUserId);
             if (info == null) {
-                Log.e(TAG, "Activity " + component + " is not installed.");
+                Slog.e(TAG, "Activity " + component + " is not installed.");
                 return null;
             }
 
             if (!info.exported) {
-                Log.e(TAG, "Activity " + component + " doesn't have 'exported' attribute.");
+                Slog.e(TAG, "Activity " + component + " doesn't have 'exported' attribute.");
                 return null;
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "Failed to get activity info for " + component, e);
+            Slog.e(TAG, "Failed to get activity info for " + component, e);
             return null;
         }
 
@@ -164,7 +163,7 @@
             }
         }
 
-        Log.e(TAG, "Activity doesn't have category Intent.CATEGORY_LAUNCHER " + component);
+        Slog.e(TAG, "Activity doesn't have category Intent.CATEGORY_LAUNCHER " + component);
         return null;
     }
 
@@ -231,33 +230,19 @@
         edit.apply();
     }
 
-    /** Returns the number of apps. */
-    public int getAppCount() {
-        return mApps.size();
+    /** Returns the list of apps. */
+    public List<AppInfo> getApps() {
+        return mApps;
     }
 
-    /** Returns the app at the given index. */
-    public AppInfo getApp(int index) {
-        return mApps.get(index);
-    }
-
-    /** Adds the app before the given index. */
-    public void addApp(int index, AppInfo appInfo) {
-        mApps.add(index, appInfo);
-    }
-
-    /** Sets the app at the given index. */
-    public void setApp(int index, AppInfo appInfo) {
-        mApps.set(index, appInfo);
-    }
-
-    /** Remove the app at the given index. */
-    public AppInfo removeApp(int index) {
-        return mApps.remove(index);
+    /** Sets the list of apps and saves it. */
+    public void setApps(List<AppInfo> apps) {
+        mApps = apps;
+        savePrefs();
     }
 
     /** Saves the current model to disk. */
-    public void savePrefs() {
+    private void savePrefs() {
         SharedPreferences.Editor edit = mPrefs.edit();
         int appCount = mApps.size();
         edit.putInt(userPrefixed(APP_COUNT_PREF), appCount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
deleted file mode 100644
index 1f71bc0..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.phone;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RecentTaskInfo;
-import android.app.ActivityManagerNative;
-import android.app.IActivityManager;
-import android.app.ITaskStackListener;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Slog;
-import android.util.SparseBooleanArray;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-
-import com.android.systemui.R;
-
-import java.util.List;
-
-/**
- * Recent task icons appearing in the navigation bar. Touching an icon brings the activity to the
- * front. The tag for each icon's View contains the RecentTaskInfo.
- */
-class NavigationBarRecents extends LinearLayout {
-    private final static boolean DEBUG = false;
-    private final static String TAG = "NavigationBarRecents";
-
-    // Maximum number of icons to show.
-    // TODO: Implement an overflow UI so the shelf can display an unlimited number of recents.
-    private final static int MAX_RECENTS = 10;
-
-    private final ActivityManager mActivityManager;
-    private final PackageManager mPackageManager;
-    private final LayoutInflater mLayoutInflater;
-    // All icons share the same long-click listener.
-    private final AppLongClickListener mAppLongClickListener;
-    private final TaskStackListenerImpl mTaskStackListener;
-
-    public NavigationBarRecents(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
-        mPackageManager = getContext().getPackageManager();
-        mLayoutInflater = LayoutInflater.from(context);
-        mAppLongClickListener = new AppLongClickListener(context);
-
-        // Listen for task stack changes and refresh when they happen. Update notifications happen
-        // on an IPC thread, so use Handler to handle the message on the main thread.
-        // TODO: This has too much latency. It only adds the icon when app launch is completed
-        // and the launch animation is done playing. This class should add the icon immediately
-        // when the launch starts.
-        Handler handler = new Handler();
-        mTaskStackListener = new TaskStackListenerImpl(handler);
-        IActivityManager iam = ActivityManagerNative.getDefault();
-        try {
-            iam.registerTaskStackListener(mTaskStackListener);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-    }
-
-    private void updateRecentApps() {
-        // TODO: Should this be getRunningTasks?
-        // TODO: Query other UserHandles?
-        List<RecentTaskInfo> recentTasks = mActivityManager.getRecentTasksForUser(
-                MAX_RECENTS,
-                ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS |
-                ActivityManager.RECENT_IGNORE_UNAVAILABLE |
-                ActivityManager.RECENT_INCLUDE_PROFILES,
-                UserHandle.USER_CURRENT);
-        if (DEBUG) Slog.d(TAG, "Got recents " + recentTasks.size());
-        removeMissingRecents(recentTasks);
-        addNewRecents(recentTasks);
-    }
-
-    // Removes any icons that disappeared from recents.
-    private void removeMissingRecents(List<RecentTaskInfo> recentTasks) {
-        // Build a set of the new task ids.
-        SparseBooleanArray newTaskIds = new SparseBooleanArray();
-        for (RecentTaskInfo task : recentTasks) {
-            newTaskIds.put(task.persistentId, true);
-        }
-
-        // Iterate through the currently displayed tasks. If they no longer exist in recents,
-        // remove them.
-        int i = 0;
-        while (i < getChildCount()) {
-            RecentTaskInfo currentTask = (RecentTaskInfo) getChildAt(i).getTag();
-            if (!newTaskIds.get(currentTask.persistentId)) {
-                if (DEBUG) Slog.d(TAG, "Removing " + currentTask.baseIntent);
-                removeViewAt(i);
-            } else {
-                i++;
-            }
-        }
-    }
-
-    // Adds new tasks at the end of the icon list.
-    private void addNewRecents(List<RecentTaskInfo> recentTasks) {
-        // Build a set of the current task ids.
-        SparseBooleanArray currentTaskIds = new SparseBooleanArray();
-        for (int i = 0; i < getChildCount(); i++) {
-            RecentTaskInfo task = (RecentTaskInfo) getChildAt(i).getTag();
-            currentTaskIds.put(task.persistentId, true);
-        }
-
-        // Add tasks that don't currently exist to the end of the view.
-        for (RecentTaskInfo task : recentTasks) {
-            // Don't overflow the list.
-            if (getChildCount() >= MAX_RECENTS) {
-                return;
-            }
-            // Don't add tasks that are already being shown.
-            if (currentTaskIds.get(task.persistentId)) {
-                continue;
-            }
-            addRecentAppButton(task);
-        }
-    }
-
-    // Adds an icon at the end of the shelf.
-    private void addRecentAppButton(RecentTaskInfo task) {
-        if (DEBUG) Slog.d(TAG, "Adding " + task.baseIntent);
-
-        // Add an icon for the task.
-        ImageView button = (ImageView) mLayoutInflater.inflate(
-                R.layout.navigation_bar_app_item, this, false /* attachToRoot */);
-        button.setOnLongClickListener(mAppLongClickListener);
-        addView(button);
-
-        ComponentName activityName = getRealActivityForTask(task);
-        CharSequence appLabel = NavigationBarApps.getAppLabel(mPackageManager, activityName);
-        button.setContentDescription(appLabel);
-
-        // Use the View's tag to store metadata for drag and drop.
-        button.setTag(task);
-
-        button.setVisibility(View.VISIBLE);
-        // Load the activity icon on a background thread.
-        AppInfo app = new AppInfo(activityName, new UserHandle(task.userId));
-        new GetActivityIconTask(mPackageManager, button).execute(app);
-
-        final int taskPersistentId = task.persistentId;
-        button.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                // Launch or bring the activity to front.
-                IActivityManager manager = ActivityManagerNative.getDefault();
-                try {
-                    manager.startActivityFromRecents(taskPersistentId, null /* options */);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Exception when activating a recent task", e);
-                } catch (IllegalArgumentException e) {
-                    Log.e(TAG, "Exception when activating a recent task", e);
-                }
-            }
-        });
-    }
-
-    private static ComponentName getRealActivityForTask(RecentTaskInfo task) {
-        // Prefer the activity that started the task.
-        if (task.realActivity != null) {
-            return task.realActivity;
-        }
-        // This should not happen, but fall back to the base intent's activity component name.
-        return task.baseIntent.getComponent();
-    }
-
-    /**
-     * A listener that updates the app buttons whenever the recents task stack changes.
-     * NOTE: This is not the right way to do this.
-     */
-    private class TaskStackListenerImpl extends ITaskStackListener.Stub {
-        // Handler to post messages to the UI thread.
-        private Handler mHandler;
-
-        public TaskStackListenerImpl(Handler handler) {
-            mHandler = handler;
-        }
-
-        @Override
-        public void onTaskStackChanged() throws RemoteException {
-            // Post the message back to the UI thread.
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    updateRecentApps();
-                }
-            });
-        }
-    }
-
-    /** Starts a drag on long-click on an app icon. */
-    private static class AppLongClickListener implements View.OnLongClickListener {
-        private final Context mContext;
-
-        public AppLongClickListener(Context context) {
-            mContext = context;
-        }
-
-        private ComponentName getLaunchComponentForPackage(String packageName, int userId) {
-            // This code is based on ApplicationPackageManager.getLaunchIntentForPackage.
-            PackageManager packageManager = mContext.getPackageManager();
-
-            // First see if the package has an INFO activity; the existence of
-            // such an activity is implied to be the desired front-door for the
-            // overall package (such as if it has multiple launcher entries).
-            Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
-            intentToResolve.addCategory(Intent.CATEGORY_INFO);
-            intentToResolve.setPackage(packageName);
-            List<ResolveInfo> ris = packageManager.queryIntentActivitiesAsUser(
-                    intentToResolve, 0, userId);
-
-            // Otherwise, try to find a main launcher activity.
-            if (ris == null || ris.size() <= 0) {
-                // reuse the intent instance
-                intentToResolve.removeCategory(Intent.CATEGORY_INFO);
-                intentToResolve.addCategory(Intent.CATEGORY_LAUNCHER);
-                intentToResolve.setPackage(packageName);
-                ris = packageManager.queryIntentActivitiesAsUser(intentToResolve, 0, userId);
-            }
-            if (ris == null || ris.size() <= 0) {
-                Log.e(TAG, "Failed to build intent for " + packageName);
-                return null;
-            }
-            return new ComponentName(ris.get(0).activityInfo.packageName,
-                    ris.get(0).activityInfo.name);
-        }
-
-        @Override
-        public boolean onLongClick(View v) {
-            ImageView icon = (ImageView) v;
-
-            // The drag will go to the pinned section, which wants to launch the main activity
-            // for the task's package.
-            RecentTaskInfo task = (RecentTaskInfo) v.getTag();
-            String packageName = getRealActivityForTask(task).getPackageName();
-            ComponentName component = getLaunchComponentForPackage(packageName, task.userId);
-            if (component == null) {
-                return false;
-            }
-
-            if (DEBUG) Slog.d(TAG, "Start drag with " + component);
-
-            NavigationBarApps.startAppDrag(
-                    icon, new AppInfo(component, new UserHandle(task.userId)));
-            return true;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 7de7a7b..f37383a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -492,14 +492,6 @@
         }
 
         updateTaskSwitchHelper();
-
-        // If using the app shelf, synchronize the current icons to the data model.
-        NavigationBarApps apps =
-                (NavigationBarApps) mCurrentView.findViewById(R.id.navigation_bar_apps);
-        if (apps != null) {
-            apps.recreateAppButtons();
-        }
-
         setNavigationIconHints(mNavigationIconHints, true);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index 950b162..310625e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -78,6 +78,13 @@
         Notification notif = sbn.getNotification();
         String groupKey = sbn.getGroupKey();
         final NotificationGroup group = mGroupMap.get(groupKey);
+        if (group == null) {
+            // When an app posts 2 different notifications as summary of the same group, then a
+            // cancellation of the first notification removes this group.
+            // This situation is not supported and we will not allow such notifications anymore in
+            // the close future. See b/23676310 for reference.
+            return;
+        }
         if (notif.isGroupSummary()) {
             group.summary = null;
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 3ad7246..814a65e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,7 +21,10 @@
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
+import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Color;
@@ -62,6 +65,8 @@
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
+import java.util.List;
+
 public class NotificationPanelView extends PanelView implements
         ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
         View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
@@ -2462,7 +2467,28 @@
         getCenterIcon().setLaunchingAffordance(launchingAffordance);
     }
 
-    public boolean canCameraGestureBeLaunched() {
-        return !mAfforanceHelper.isSwipingInProgress();
+    /**
+     * Whether the camera application can be launched for the camera launch gesture.
+     *
+     * @param keyguardIsShowing whether keyguard is being shown
+     */
+    public boolean canCameraGestureBeLaunched(boolean keyguardIsShowing) {
+        ResolveInfo resolveInfo = mKeyguardBottomArea.resolveCameraIntent();
+        String packageToLaunch = (resolveInfo == null || resolveInfo.activityInfo == null)
+                ? null : resolveInfo.activityInfo.packageName;
+        return packageToLaunch != null &&
+               (keyguardIsShowing || !isForegroundApp(packageToLaunch)) &&
+               !mAfforanceHelper.isSwipingInProgress();
+    }
+
+    /**
+     * Return true if the applications with the package name is running in foreground.
+     *
+     * @param pkgName application package name.
+     */
+    private boolean isForegroundApp(String pkgName) {
+        ActivityManager am = getContext().getSystemService(ActivityManager.class);
+        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1);
+        return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
     }
 }
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 7b04da0..55fbb2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -3794,12 +3794,9 @@
         // down on the lockscreen), clear notification LED, vibration,
         // ringing.
         // Other transitions are covered in handleVisibleToUserChanged().
-        if (state != mState && mVisible && state == StatusBarState.SHADE_LOCKED) {
-            try {
-                mBarService.clearNotificationEffects();
-            } catch (RemoteException e) {
-                // Ignore.
-            }
+        if (state != mState && mVisible && (state == StatusBarState.SHADE_LOCKED
+                || (state == StatusBarState.SHADE && isGoingToNotificationShade()))) {
+            clearNotificationEffects();
         }
         mState = state;
         mGroupManager.setStatusBarState(state);
@@ -4150,7 +4147,8 @@
 
     @Override
     public void onCameraLaunchGestureDetected() {
-        if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+        if (!mNotificationPanel.canCameraGestureBeLaunched(
+                mStatusBarKeyguardViewManager.isShowing() && mExpandedVisible)) {
             return;
         }
         if (!mDeviceInteractive) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 12434ac..385c5d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -36,6 +36,11 @@
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.IntentTile;
 import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.QAirplaneTile;
+import com.android.systemui.qs.tiles.QBluetoothTile;
+import com.android.systemui.qs.tiles.QFlashlightTile;
+import com.android.systemui.qs.tiles.QRotationLockTile;
+import com.android.systemui.qs.tiles.QWifiTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.WifiTile;
 import com.android.systemui.statusbar.policy.BluetoothController;
@@ -64,7 +69,7 @@
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
-    protected static final String TILES_SETTING = "sysui_qs_tiles";
+    public static final String TILES_SETTING = "sysui_qs_tiles";
 
     private final Context mContext;
     private final PhoneStatusBar mStatusBar;
@@ -243,8 +248,8 @@
     }
 
     protected QSTile<?> createTile(String tileSpec) {
-        if (tileSpec.equals("wifi")) return new WifiTile(this);
-        else if (tileSpec.equals("bt")) return new BluetoothTile(this);
+        if (tileSpec.equals("wifi")) return new WifiTile(this, false);
+        else if (tileSpec.equals("bt")) return new BluetoothTile(this, false);
         else if (tileSpec.equals("inversion")) return new ColorInversionTile(this);
         else if (tileSpec.equals("cell")) return new CellularTile(this);
         else if (tileSpec.equals("airplane")) return new AirplaneModeTile(this);
@@ -254,6 +259,16 @@
         else if (tileSpec.equals("location")) return new LocationTile(this);
         else if (tileSpec.equals("cast")) return new CastTile(this);
         else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
+        // Detail only versions of wifi and bluetooth.
+        else if (tileSpec.equals("dwifi")) return new WifiTile(this, true);
+        else if (tileSpec.equals("dbt")) return new BluetoothTile(this, true);
+        // Quick tiles, no text.
+        else if (tileSpec.equals("qwifi")) return new QWifiTile(this);
+        else if (tileSpec.equals("qbt")) return new QBluetoothTile(this);
+        else if (tileSpec.equals("qairplane")) return new QAirplaneTile(this);
+        else if (tileSpec.equals("qrotation")) return new QRotationLockTile(this);
+        else if (tileSpec.equals("qflashlight")) return new QFlashlightTile(this);
+        // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
     }
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 d0604c5..e26f423 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -24,6 +24,7 @@
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewRootImpl;
 import android.view.WindowManagerGlobal;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -533,4 +534,8 @@
     public void showBouncerMessage(String message, int color) {
         mBouncer.showMessage(message, color);
     }
+
+    public ViewRootImpl getViewRootImpl() {
+        return mPhoneStatusBar.getStatusBarView().getViewRootImpl();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 6d791bf..0f9dd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnInfo;
@@ -62,8 +63,9 @@
     private final IConnectivityManager mConnectivityManagerService;
     private final DevicePolicyManager mDevicePolicyManager;
     private final UserManager mUserManager;
-    private final ArrayList<SecurityControllerCallback> mCallbacks
-            = new ArrayList<SecurityControllerCallback>();
+
+    @GuardedBy("mCallbacks")
+    private final ArrayList<SecurityControllerCallback> mCallbacks = new ArrayList<>();
 
     private SparseArray<VpnConfig> mCurrentVpns = new SparseArray<>();
     private int mCurrentUserId;
@@ -161,16 +163,20 @@
 
     @Override
     public void removeCallback(SecurityControllerCallback callback) {
-        if (callback == null) return;
-        if (DEBUG) Log.d(TAG, "removeCallback " + callback);
-        mCallbacks.remove(callback);
+        synchronized (mCallbacks) {
+            if (callback == null) return;
+            if (DEBUG) Log.d(TAG, "removeCallback " + callback);
+            mCallbacks.remove(callback);
+        }
     }
 
     @Override
     public void addCallback(SecurityControllerCallback callback) {
-        if (callback == null || mCallbacks.contains(callback)) return;
-        if (DEBUG) Log.d(TAG, "addCallback " + callback);
-        mCallbacks.add(callback);
+        synchronized (mCallbacks) {
+            if (callback == null || mCallbacks.contains(callback)) return;
+            if (DEBUG) Log.d(TAG, "addCallback " + callback);
+            mCallbacks.add(callback);
+        }
     }
 
     @Override
@@ -203,8 +209,10 @@
     }
 
     private void fireCallbacks() {
-        for (SecurityControllerCallback callback : mCallbacks) {
-            callback.onStateChanged();
+        synchronized (mCallbacks) {
+            for (SecurityControllerCallback callback : mCallbacks) {
+                callback.onStateChanged();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
new file mode 100644
index 0000000..343a231
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
@@ -0,0 +1,26 @@
+package com.android.systemui.tuner;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.util.AttributeSet;
+
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+public class QSPagingSwitch extends TunerSwitch {
+
+    private static final String QS_PAGE_TILES =
+            "dwifi,dbt,inversion,dnd,cell,airplane,rotation,flashlight,location,"
+             + "hotspot,qwifi,qbt,qrotation,qflashlight,qairplane,cast";
+
+    public QSPagingSwitch(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected boolean persistBoolean(boolean value) {
+        Settings.Secure.putString(getContext().getContentResolver(), QSTileHost.TILES_SETTING,
+                value ? QS_PAGE_TILES : "default");
+        return super.persistBoolean(value);
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 37ac098..772f866 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -389,10 +389,11 @@
             mView = super.createTileView(context);
             return mView;
         }
-
+        
         @Override
-        public boolean supportsDualTargets() {
-            return "wifi".equals(mSpec) || "bt".equals(mSpec);
+        public int getTileType() {
+            return "wifi".equals(mSpec) || "bt".equals(mSpec) ? QSTileView.QS_TYPE_DUAL
+                    : QSTileView.QS_TYPE_NORMAL;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 96ad756..920f875 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -36,6 +36,8 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
 
@@ -55,6 +57,8 @@
 
     private SwitchPreference mBatteryPct;
 
+    private Preference mQsTuner;
+
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
@@ -62,7 +66,8 @@
         getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
         setHasOptionsMenu(true);
 
-        findPreference(KEY_QS_TUNER).setOnPreferenceClickListener(new OnPreferenceClickListener() {
+        mQsTuner = findPreference(KEY_QS_TUNER);
+        mQsTuner.setOnPreferenceClickListener(new OnPreferenceClickListener() {
             @Override
             public boolean onPreferenceClick(Preference preference) {
                 FragmentTransaction ft = getFragmentManager().beginTransaction();
@@ -96,6 +101,13 @@
                         }
                     }).show();
         }
+        TunerService.get(getContext()).addTunable(mQsPaging, QSPanel.QS_PAGED_PANEL);
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        TunerService.get(getContext()).removeTunable(mQsPaging);
     }
 
     @Override
@@ -167,4 +179,12 @@
             return true;
         }
     };
+
+    private final Tunable mQsPaging = new Tunable() {
+        @Override
+        public void onTuningChanged(String key, String newValue) {
+            // Only enable QS rearranging when paging is off, because its very broken.
+            mQsTuner.setEnabled(newValue == null || Integer.parseInt(newValue) == 0);
+        }
+    };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
index 0740e08..54078b0 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerSwitch.java
@@ -1,16 +1,23 @@
 package com.android.systemui.tuner;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.preference.SwitchPreference;
 import android.provider.Settings;
 import android.util.AttributeSet;
 
+import com.android.systemui.R;
 import com.android.systemui.tuner.TunerService.Tunable;
 
 public class TunerSwitch extends SwitchPreference implements Tunable {
 
+    private final boolean mDefault;
+
     public TunerSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TunerSwitch);
+        mDefault = a.getBoolean(R.styleable.TunerSwitch_defValue, false);
     }
 
     @Override
@@ -27,7 +34,7 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        setChecked(newValue != null && Integer.parseInt(newValue) != 0);
+        setChecked(newValue != null ? Integer.parseInt(newValue) != 0 : mDefault);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 95a8d39..6475cbf 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -421,8 +421,9 @@
                         }
                     }
                 } else {
-                    final boolean vmute = row.ss.level == 0;
-                    mController.setStreamVolume(stream, vmute ? row.lastAudibleLevel : 0);
+                    final boolean vmute = row.ss.level == row.ss.levelMin;
+                    mController.setStreamVolume(stream,
+                            vmute ? row.lastAudibleLevel : row.ss.levelMin);
                 }
                 row.userAttempt = 0;  // reset the grace period, slider should update immediately
             }
@@ -1024,6 +1025,7 @@
                 final int minProgress = mRow.ss.levelMin * 100;
                 if (progress < minProgress) {
                     seekBar.setProgress(minProgress);
+                    progress = minProgress;
                 }
             }
             final int userLevel = getImpliedLevel(seekBar, progress);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
index fce6b29..e7a40d7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarAppsModelTest.java
@@ -218,11 +218,12 @@
     /** Tests initializing the model from SharedPreferences. */
     public void testInitializeFromPrefs() {
         initializeModelFromPrefs();
-        assertEquals(2, mModel.getAppCount());
-        assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(4), mModel.getApp(0).getUser());
-        assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), mModel.getApp(1).getUser());
+        List<AppInfo> apps = mModel.getApps();
+        assertEquals(2, apps.size());
+        assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
+        assertEquals(new UserHandle(4), apps.get(0).getUser());
+        assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
+        assertEquals(new UserHandle(5), apps.get(1).getUser());
     }
 
     /** Tests initializing the model when the SharedPreferences aren't available. */
@@ -247,11 +248,12 @@
 
         // Setting the user should load the installed activities.
         mModel.setCurrentUser(2);
-        assertEquals(2, mModel.getAppCount());
-        assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(2), mModel.getApp(0).getUser());
-        assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
-        assertEquals(new UserHandle(2), mModel.getApp(1).getUser());
+        List<AppInfo> apps = mModel.getApps();
+        assertEquals(2, apps.size());
+        assertEquals("package1/class1", apps.get(0).getComponentName().flattenToString());
+        assertEquals(new UserHandle(2), apps.get(0).getUser());
+        assertEquals("package2/class2", apps.get(1).getComponentName().flattenToString());
+        assertEquals(new UserHandle(2), apps.get(1).getUser());
         InOrder order = inOrder(mMockEdit);
         order.verify(mMockEdit).apply();
         order.verify(mMockEdit).putInt("222|app_count", 2);
@@ -293,9 +295,10 @@
 
         // Initializing the model should load from prefs and skip the missing one.
         mModel.setCurrentUser(2);
-        assertEquals(1, mModel.getAppCount());
-        assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), mModel.getApp(0).getUser());
+        List<AppInfo> apps = mModel.getApps();
+        assertEquals(1, apps.size());
+        assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
+        assertEquals(new UserHandle(5), apps.get(0).getUser());
         InOrder order = inOrder(mMockEdit);
         order.verify(mMockEdit).putInt("222|app_count", 1);
         order.verify(mMockEdit).putString("222|app_0", "package0/class0");
@@ -333,9 +336,10 @@
 
         // Initializing the model should load from prefs and skip the unlauncheable one.
         mModel.setCurrentUser(2);
-        assertEquals(1, mModel.getAppCount());
-        assertEquals("package0/class0", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(new UserHandle(5), mModel.getApp(0).getUser());
+        List<AppInfo> apps = mModel.getApps();
+        assertEquals(1, apps.size());
+        assertEquals("package0/class0", apps.get(0).getComponentName().flattenToString());
+        assertEquals(new UserHandle(5), apps.get(0).getUser());
 
         // Once an unlauncheable app is detected, the model should save all apps excluding the
         // unlauncheable one.
@@ -350,7 +354,7 @@
     public void testSavePrefs() {
         initializeModelFromPrefs();
 
-        mModel.savePrefs();
+        mModel.setApps(mModel.getApps());
         verify(mMockEdit).putInt("222|app_count", 2);
         verify(mMockEdit).putString("222|app_0", "package1/class1");
         verify(mMockEdit).putLong("222|app_user_0", 444L);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 57769e7..7051b52 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -205,9 +205,7 @@
 
     private final UserManager mUserManager;
 
-    private final LockPatternUtils mLockPatternUtils;
-
-    private int mCurrentUserId = UserHandle.USER_OWNER;
+    private int mCurrentUserId = UserHandle.USER_SYSTEM;
 
     //TODO: Remove this hack
     private boolean mInitialized;
@@ -230,7 +228,6 @@
         mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
         mSecurityPolicy = new SecurityPolicy();
         mMainHandler = new MainHandler(mContext.getMainLooper());
-        mLockPatternUtils = new LockPatternUtils(context);
         registerBroadcastReceivers();
         new AccessibilityContentObserver(mMainHandler).register(
                 context.getContentResolver());
@@ -866,17 +863,18 @@
     }
 
     // Called only during settings restore; currently supports only the owner user
+    // TODO: http://b/22388012
     void restoreEnabledAccessibilityServicesLocked(String oldSetting, String newSetting) {
         readComponentNamesFromStringLocked(oldSetting, mTempComponentNameSet, false);
         readComponentNamesFromStringLocked(newSetting, mTempComponentNameSet, true);
 
-        UserState userState = getUserStateLocked(UserHandle.USER_OWNER);
+        UserState userState = getUserStateLocked(UserHandle.USER_SYSTEM);
         userState.mEnabledServices.clear();
         userState.mEnabledServices.addAll(mTempComponentNameSet);
         persistComponentNamesToSettingLocked(
                 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                 userState.mEnabledServices,
-                UserHandle.USER_OWNER);
+                UserHandle.USER_SYSTEM);
         onUserStateChangedLocked(userState);
     }
 
@@ -1646,10 +1644,6 @@
         DisplayAdjustmentUtils.applyAdjustments(mContext, userState.mUserId);
     }
 
-    private boolean hasRunningServicesLocked(UserState userState) {
-        return !userState.mBoundServices.isEmpty() || !userState.mBindingServices.isEmpty();
-    }
-
     private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
         IBinder windowToken = mGlobalWindowTokens.get(windowId);
         if (windowToken == null) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index f724749..ff02b94 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1955,10 +1955,12 @@
                 .setPackage(pkgInfo.packageName);
         List<ResolveInfo> hosts = mPackageManager.queryIntentServicesAsUser(
                 intent, 0, UserHandle.USER_OWNER);
-        final int N = hosts.size();
-        for (int i = 0; i < N; i++) {
-            final ServiceInfo info = hosts.get(i).serviceInfo;
-            tryBindTransport(info);
+        if (hosts != null) {
+            final int N = hosts.size();
+            for (int i = 0; i < N; i++) {
+                final ServiceInfo info = hosts.get(i).serviceInfo;
+                tryBindTransport(info);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 4288fa2..882899e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -177,7 +177,7 @@
 
         private static final long DEFAULT_MIN_FUTURITY = 5 * 1000;
         private static final long DEFAULT_MIN_INTERVAL = 60 * 1000;
-        private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000;
+        private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000;
         private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000;
 
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index 6a67316..a0b5c15 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -58,9 +58,6 @@
     /** Current measurement state. */
     private int mState;
 
-    /** Threshold angle in degrees beyond which the device is considered moving. */
-    private final float THRESHOLD_ANGLE = 2f;
-
     /** Threshold energy above which the device is considered moving. */
     private final float THRESHOLD_ENERGY = 5f;
 
@@ -88,6 +85,9 @@
     private SensorManager mSensorManager;
     private PowerManager.WakeLock mWakeLock;
 
+    /** Threshold angle in degrees beyond which the device is considered moving. */
+    private final float mThresholdAngle;
+
     /** The minimum number of samples required to detect AnyMotion. */
     private int mNumSufficientSamples;
 
@@ -106,7 +106,7 @@
     private DeviceIdleCallback mCallback = null;
 
     public AnyMotionDetector(PowerManager pm, Handler handler, SensorManager sm,
-            DeviceIdleCallback callback) {
+            DeviceIdleCallback callback, float thresholdAngle) {
         if (DEBUG) Slog.d(TAG, "AnyMotionDetector instantiated.");
         mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
         mWakeLock.setReferenceCounted(false);
@@ -116,6 +116,7 @@
         mMeasurementInProgress = false;
         mState = STATE_INACTIVE;
         mCallback = callback;
+        mThresholdAngle = thresholdAngle;
         mRunningStats = new RunningSignalStats();
         mNumSufficientSamples = (int) Math.ceil(
                 ((double)ORIENTATION_MEASUREMENT_DURATION_MILLIS / SAMPLING_INTERVAL_MILLIS));
@@ -224,8 +225,9 @@
         Vector3 previousGravityVectorNormalized = mPreviousGravityVector.normalized();
         Vector3 currentGravityVectorNormalized = mCurrentGravityVector.normalized();
         float angle = previousGravityVectorNormalized.angleBetween(currentGravityVectorNormalized);
-        if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle);
-        if ((angle < THRESHOLD_ANGLE) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
+        if (DEBUG) Slog.d(TAG, "getStationaryStatus: angle = " + angle
+                + " energy = " + mRunningStats.getEnergy());
+        if ((angle < mThresholdAngle) && (mRunningStats.getEnergy() < THRESHOLD_ENERGY)) {
             return RESULT_STATIONARY;
         } else if (Float.isNaN(angle)) {
           /**
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e19447d..2bcee91 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1524,10 +1524,14 @@
 
             final long ident = Binder.clearCallingIdentity();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(intent.getAction())) {
+                final NetworkInfo ni = intent.getParcelableExtra(
+                        ConnectivityManager.EXTRA_NETWORK_INFO);
+                if (ni.getType() == ConnectivityManager.TYPE_MOBILE_SUPL) {
+                    intent.setAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
+                    intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                }
                 final IBatteryStats bs = BatteryStatsService.getService();
                 try {
-                    NetworkInfo ni = intent.getParcelableExtra(
-                            ConnectivityManager.EXTRA_NETWORK_INFO);
                     bs.noteConnectivityChanged(intent.getIntExtra(
                             ConnectivityManager.EXTRA_NETWORK_TYPE, ConnectivityManager.TYPE_NONE),
                             ni != null ? ni.getState().toString() : "?");
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 80fd441..46fd28a 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -128,7 +128,8 @@
     private boolean mNotMoving;
     private boolean mLocating;
     private boolean mLocated;
-    private boolean mHaveGps;
+    private boolean mHasGps;
+    private boolean mHasNetworkLocation;
     private Location mLastGenericLocation;
     private Location mLastGpsLocation;
 
@@ -882,17 +883,37 @@
                 mDisplayManager = (DisplayManager) getContext().getSystemService(
                         Context.DISPLAY_SERVICE);
                 mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
-                mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
-                mLocationManager = (LocationManager) getContext().getSystemService(
-                        Context.LOCATION_SERVICE);
-                mLocationRequest = new LocationRequest()
-                    .setQuality(LocationRequest.ACCURACY_FINE)
-                    .setInterval(0)
-                    .setFastestInterval(0)
-                    .setNumUpdates(1);
+                int sigMotionSensorId = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
+                if (sigMotionSensorId > 0) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+                }
+                if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_WRIST_TILT_GESTURE);
+                }
+                if (mSigMotionSensor == null) {
+                    // As a last ditch, fall back to SMD.
+                    mSigMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_SIGNIFICANT_MOTION);
+                }
+                if (getContext().getResources().getBoolean(
+                        com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
+                    mLocationManager = (LocationManager) getContext().getSystemService(
+                            Context.LOCATION_SERVICE);
+                    mLocationRequest = new LocationRequest()
+                        .setQuality(LocationRequest.ACCURACY_FINE)
+                        .setInterval(0)
+                        .setFastestInterval(0)
+                        .setNumUpdates(1);
+                }
+
+                float angleThreshold = getContext().getResources().getInteger(
+                        com.android.internal.R.integer.config_autoPowerModeThresholdAngle) / 100f;
                 mAnyMotionDetector = new AnyMotionDetector(
                         (PowerManager) getContext().getSystemService(Context.POWER_SERVICE),
-                        mHandler, mSensorManager, this);
+                        mHandler, mSensorManager, this, angleThreshold);
 
                 Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
                         .setPackage("android")
@@ -1279,17 +1300,30 @@
                 EventLogTags.writeDeviceIdle(mState, "step");
                 cancelSensingAlarmLocked();
                 scheduleSensingAlarmLocked(mConstants.LOCATING_TIMEOUT);
-                mLocating = true;
-                mLocationManager.requestLocationUpdates(mLocationRequest, mGenericLocationListener,
-                        mHandler.getLooper());
-                if (mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
-                    mHaveGps = true;
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.NETWORK_PROVIDER) != null) {
+                    mLocationManager.requestLocationUpdates(mLocationRequest,
+                            mGenericLocationListener, mHandler.getLooper());
+                    mLocating = true;
+                } else {
+                    mHasNetworkLocation = false;
+                }
+                if (mLocationManager != null
+                        && mLocationManager.getProvider(LocationManager.GPS_PROVIDER) != null) {
+                    mHasGps = true;
                     mLocationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 5,
                             mGpsLocationListener, mHandler.getLooper());
+                    mLocating = true;
                 } else {
-                    mHaveGps = false;
+                    mHasGps = false;
                 }
-                break;
+                // If we have a location provider, we're all set, the listeners will move state
+                // forward.
+                if (mLocating) {
+                    break;
+                }
+
+                // Otherwise, we have to move from locating into idle maintenance.
             case STATE_LOCATING:
                 cancelSensingAlarmLocked();
                 cancelLocatingLocked();
@@ -1346,7 +1380,7 @@
         }
         if (DEBUG) Slog.d(TAG, "Generic location: " + location);
         mLastGenericLocation = new Location(location);
-        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHaveGps) {
+        if (location.getAccuracy() > mConstants.LOCATION_ACCURACY && mHasGps) {
             return;
         }
         mLocated = true;
@@ -1413,9 +1447,9 @@
     void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
         if (mSigMotionSensor == null) {
-            // If there is no significant motion sensor on this device, then we won't schedule
+            // If there is no motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
-            // turns off normal exeuction of device idling, although it is still possible to
+            // turns off normal execution of device idling, although it is still possible to
             // manually poke it by pretending like the alarm is going off.
             return;
         }
@@ -1902,8 +1936,9 @@
             pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
             pw.print("  mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
                     pw.println(mNotMoving);
-            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHaveGps=");
-                    pw.print(mHaveGps); pw.print(" mLocated="); pw.println(mLocated);
+            pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
+                    pw.print(mHasGps); pw.print(" mHasNetwork=");
+                    pw.print(mHasNetworkLocation); pw.print(" mLocated="); pw.println(mLocated);
             if (mLastGenericLocation != null) {
                 pw.print("  mLastGenericLocation="); pw.println(mLastGenericLocation);
             }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 468ead0..885c765 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -307,6 +307,7 @@
         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
         intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
         intentFilter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+        intentFilter.addAction(Intent.ACTION_SHUTDOWN);
 
         mContext.registerReceiverAsUser(new BroadcastReceiver() {
             @Override
@@ -317,12 +318,36 @@
                 } else if (Intent.ACTION_MANAGED_PROFILE_ADDED.equals(action)
                         || Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
                     updateUserProfiles(mCurrentUserId);
+                } else if (Intent.ACTION_SHUTDOWN.equals(action)) {
+                    shutdownComponents();
                 }
             }
         }, UserHandle.ALL, intentFilter, null, mLocationHandler);
     }
 
     /**
+     * Provides a way for components held by the {@link LocationManagerService} to clean-up
+     * gracefully on system's shutdown.
+     *
+     * NOTES:
+     * 1) Only provides a chance to clean-up on an opt-in basis. This guarantees back-compat
+     * support for components that do not wish to handle such event.
+     */
+    private void shutdownComponents() {
+        if(D) Log.d(TAG, "Shutting down components...");
+
+        LocationProviderInterface gpsProvider = mProvidersByName.get(LocationManager.GPS_PROVIDER);
+        if (gpsProvider != null && gpsProvider.isEnabled()) {
+            gpsProvider.disable();
+        }
+
+        FlpHardwareProvider flpHardwareProvider = FlpHardwareProvider.getInstance(mContext);
+        if (FlpHardwareProvider.isSupported() && flpHardwareProvider != null) {
+            flpHardwareProvider.cleanup();
+        }
+    }
+
+    /**
      * Makes a list of userids that are related to the current user. This is
      * relevant when using managed profiles. Otherwise the list only contains
      * the current user.
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 94316fe..e8b90d8 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -25,6 +25,7 @@
 import android.os.RemoteException;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.service.persistentdata.IPersistentDataBlockService;
 import android.util.Slog;
 
@@ -84,7 +85,7 @@
         mContext = context;
         mDataBlockFile = SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP);
         mBlockDeviceSize = -1; // Load lazily
-        mAllowedUid = getAllowedUid(UserHandle.USER_OWNER);
+        mAllowedUid = getAllowedUid(UserHandle.USER_SYSTEM);
     }
 
     private int getAllowedUid(int userHandle) {
@@ -131,9 +132,12 @@
         }
     }
 
-    private void enforceIsOwner() {
-        if (!Binder.getCallingUserHandle().isOwner()) {
-            throw new SecurityException("Only the Owner is allowed to change OEM unlock state");
+    private void enforceIsAdmin() {
+        final int userId = UserHandle.getCallingUserId();
+        final boolean isAdmin = UserManager.get(mContext).isUserAdmin(userId);
+        if (!isAdmin) {
+            throw new SecurityException(
+                    "Only the Admin user is allowed to change OEM unlock state");
         }
     }
     private int getTotalDataSizeLocked(DataInputStream inputStream) throws IOException {
@@ -434,7 +438,7 @@
                 return;
             }
             enforceOemUnlockPermission();
-            enforceIsOwner();
+            enforceIsAdmin();
 
             synchronized (mLock) {
                 doSetOemUnlockEnabledLocked(enabled);
diff --git a/services/core/java/com/android/server/SystemServiceManager.java b/services/core/java/com/android/server/SystemServiceManager.java
index fda6479..92e6814 100644
--- a/services/core/java/com/android/server/SystemServiceManager.java
+++ b/services/core/java/com/android/server/SystemServiceManager.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.content.Context;
+import android.os.Trace;
 import android.util.Slog;
 
 import java.lang.reflect.Constructor;
@@ -75,43 +76,48 @@
      */
     @SuppressWarnings("unchecked")
     public <T extends SystemService> T startService(Class<T> serviceClass) {
-        final String name = serviceClass.getName();
-        Slog.i(TAG, "Starting " + name);
-
-        // Create the service.
-        if (!SystemService.class.isAssignableFrom(serviceClass)) {
-            throw new RuntimeException("Failed to create " + name
-                    + ": service must extend " + SystemService.class.getName());
-        }
-        final T service;
         try {
-            Constructor<T> constructor = serviceClass.getConstructor(Context.class);
-            service = constructor.newInstance(mContext);
-        } catch (InstantiationException ex) {
-            throw new RuntimeException("Failed to create service " + name
-                    + ": service could not be instantiated", ex);
-        } catch (IllegalAccessException ex) {
-            throw new RuntimeException("Failed to create service " + name
-                    + ": service must have a public constructor with a Context argument", ex);
-        } catch (NoSuchMethodException ex) {
-            throw new RuntimeException("Failed to create service " + name
-                    + ": service must have a public constructor with a Context argument", ex);
-        } catch (InvocationTargetException ex) {
-            throw new RuntimeException("Failed to create service " + name
-                    + ": service constructor threw an exception", ex);
-        }
+            final String name = serviceClass.getName();
+            Slog.i(TAG, "Starting " + name);
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartService " + name);
 
-        // Register it.
-        mServices.add(service);
+            // Create the service.
+            if (!SystemService.class.isAssignableFrom(serviceClass)) {
+                throw new RuntimeException("Failed to create " + name
+                        + ": service must extend " + SystemService.class.getName());
+            }
+            final T service;
+            try {
+                Constructor<T> constructor = serviceClass.getConstructor(Context.class);
+                service = constructor.newInstance(mContext);
+            } catch (InstantiationException ex) {
+                throw new RuntimeException("Failed to create service " + name
+                        + ": service could not be instantiated", ex);
+            } catch (IllegalAccessException ex) {
+                throw new RuntimeException("Failed to create service " + name
+                        + ": service must have a public constructor with a Context argument", ex);
+            } catch (NoSuchMethodException ex) {
+                throw new RuntimeException("Failed to create service " + name
+                        + ": service must have a public constructor with a Context argument", ex);
+            } catch (InvocationTargetException ex) {
+                throw new RuntimeException("Failed to create service " + name
+                        + ": service constructor threw an exception", ex);
+            }
 
-        // Start it.
-        try {
-            service.onStart();
-        } catch (RuntimeException ex) {
-            throw new RuntimeException("Failed to start service " + name
-                    + ": onStart threw an exception", ex);
+            // Register it.
+            mServices.add(service);
+
+            // Start it.
+            try {
+                service.onStart();
+            } catch (RuntimeException ex) {
+                throw new RuntimeException("Failed to start service " + name
+                        + ": onStart threw an exception", ex);
+            }
+            return service;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
-        return service;
     }
 
     /**
@@ -127,18 +133,22 @@
         mCurrentPhase = phase;
 
         Slog.i(TAG, "Starting phase " + mCurrentPhase);
-
-        final int serviceLen = mServices.size();
-        for (int i = 0; i < serviceLen; i++) {
-            final SystemService service = mServices.get(i);
-            try {
-                service.onBootPhase(mCurrentPhase);
-            } catch (Exception ex) {
-                throw new RuntimeException("Failed to boot service "
-                        + service.getClass().getName()
-                        + ": onBootPhase threw an exception during phase "
-                        + mCurrentPhase, ex);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "OnBootPhase " + phase);
+            final int serviceLen = mServices.size();
+            for (int i = 0; i < serviceLen; i++) {
+                final SystemService service = mServices.get(i);
+                try {
+                    service.onBootPhase(mCurrentPhase);
+                } catch (Exception ex) {
+                    throw new RuntimeException("Failed to boot service "
+                            + service.getClass().getName()
+                            + ": onBootPhase threw an exception during phase "
+                            + mCurrentPhase, ex);
+                }
             }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
     }
 
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 8b0e6f2..7aef38d 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -511,10 +511,17 @@
         Account[] sharedAccounts = getSharedAccountsAsUser(userId);
         if (sharedAccounts == null || sharedAccounts.length == 0) return;
         Account[] accounts = getAccountsAsUser(null, userId);
+        int parentUserId = UserManager.isSplitSystemUser()
+                ? mUserManager.getUserInfo(userId).restrictedProfileParentId
+                : UserHandle.USER_SYSTEM;
+        if (parentUserId < 0) {
+            Log.w(TAG, "User " + userId + " has shared accounts, but no parent user");
+            return;
+        }
         for (Account sa : sharedAccounts) {
             if (ArrayUtils.contains(accounts, sa)) continue;
             // Account doesn't exist. Copy it now.
-            copyAccountToUser(null /*no response*/, sa, UserHandle.USER_OWNER, userId);
+            copyAccountToUser(null /*no response*/, sa, parentUserId, userId);
         }
     }
 
@@ -740,7 +747,7 @@
 
     @Override
     public void copyAccountToUser(final IAccountManagerResponse response, final Account account,
-            int userFrom, int userTo) {
+            final int userFrom, int userTo) {
         int callingUid = Binder.getCallingUid();
         if (isCrossUser(callingUid, UserHandle.USER_ALL)) {
             throw new SecurityException("Calling copyAccountToUser requires "
@@ -784,7 +791,7 @@
                     if (result != null
                             && result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
                         // Create a Session for the target user and pass in the bundle
-                        completeCloningAccount(response, result, account, toAccounts);
+                        completeCloningAccount(response, result, account, toAccounts, userFrom);
                     } else {
                         super.onResult(result);
                     }
@@ -851,7 +858,8 @@
     }
 
     private void completeCloningAccount(IAccountManagerResponse response,
-            final Bundle accountCredentials, final Account account, final UserAccounts targetUser) {
+            final Bundle accountCredentials, final Account account, final UserAccounts targetUser,
+            final int parentUserId){
         long id = clearCallingIdentity();
         try {
             new Session(targetUser, response, account.type, false,
@@ -866,9 +874,9 @@
                 @Override
                 public void run() throws RemoteException {
                     // Confirm that the owner's account still exists before this step.
-                    UserAccounts owner = getUserAccounts(UserHandle.USER_OWNER);
+                    UserAccounts owner = getUserAccounts(parentUserId);
                     synchronized (owner.cacheLock) {
-                        for (Account acc : getAccounts(UserHandle.USER_OWNER)) {
+                        for (Account acc : getAccounts(parentUserId)) {
                             if (acc.equals(account)) {
                                 mAuthenticator.addAccountFromCredentials(
                                         this, account, accountCredentials);
@@ -949,27 +957,27 @@
             }
             sendAccountsChangedBroadcast(accounts.userId);
         }
-        if (accounts.userId == UserHandle.USER_OWNER) {
-            addAccountToLimitedUsers(account);
+        if (getUserManager().getUserInfo(accounts.userId).canHaveProfile()) {
+            addAccountToLinkedRestrictedUsers(account, accounts.userId);
         }
         return true;
     }
 
     /**
-     * Adds the account to all limited users as shared accounts. If the user is currently
+     * Adds the account to all linked restricted users as shared accounts. If the user is currently
      * running, then clone the account too.
      * @param account the account to share with limited users
+     *
      */
-    private void addAccountToLimitedUsers(Account account) {
+    private void addAccountToLinkedRestrictedUsers(Account account, int parentUserId) {
         List<UserInfo> users = getUserManager().getUsers();
         for (UserInfo user : users) {
-            if (user.isRestricted()) {
+            if (user.isRestricted() && (parentUserId == user.restrictedProfileParentId)) {
                 addSharedAccountAsUser(account, user.id);
                 try {
                     if (ActivityManagerNative.getDefault().isUserRunning(user.id, false)) {
                         mMessageHandler.sendMessage(mMessageHandler.obtainMessage(
-                                MESSAGE_COPY_SHARED_ACCOUNT, UserHandle.USER_OWNER, user.id,
-                                account));
+                                MESSAGE_COPY_SHARED_ACCOUNT, parentUserId, user.id, account));
                     }
                 } catch (RemoteException re) {
                     // Shouldn't happen
@@ -1172,14 +1180,16 @@
                           new AtomicReference<String>(accountToRename.name));
                     resultAccount = renamedAccount;
 
-                    if (accounts.userId == UserHandle.USER_OWNER) {
+                    int parentUserId = accounts.userId;
+                    if (canHaveProfile(parentUserId)) {
                         /*
-                         * Owner's account was renamed, rename the account for
+                         * Owner or system user account was renamed, rename the account for
                          * those users with which the account was shared.
                          */
                         List<UserInfo> users = mUserManager.getUsers(true);
                         for (UserInfo user : users) {
-                            if (!user.isPrimary() && user.isRestricted()) {
+                            if (user.isRestricted()
+                                    && (user.restrictedProfileParentId == parentUserId)) {
                                 renameSharedAccountAsUser(accountToRename, newName, user.id);
                             }
                         }
@@ -1191,6 +1201,11 @@
         return resultAccount;
     }
 
+    private boolean canHaveProfile(final int parentUserId) {
+        final UserInfo userInfo = mUserManager.getUserInfo(parentUserId);
+        return userInfo != null && userInfo.canHaveProfile();
+    }
+
     @Override
     public void removeAccount(IAccountManagerResponse response, Account account,
             boolean expectActivityLaunch) {
@@ -1304,7 +1319,7 @@
         logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
         long identityToken = clearCallingIdentity();
         try {
-            return removeAccountInternal(accounts, account);
+            return removeAccountInternal(accounts, account, callingUid);
         } finally {
             restoreCallingIdentity(identityToken);
         }
@@ -1337,7 +1352,7 @@
                     && !result.containsKey(AccountManager.KEY_INTENT)) {
                 final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
                 if (removalAllowed) {
-                    removeAccountInternal(mAccounts, mAccount);
+                    removeAccountInternal(mAccounts, mAccount, getCallingUid());
                 }
                 IAccountManagerResponse response = getResponseAndClose();
                 if (response != null) {
@@ -1360,10 +1375,10 @@
 
     /* For testing */
     protected void removeAccountInternal(Account account) {
-        removeAccountInternal(getUserAccountsForCaller(), account);
+        removeAccountInternal(getUserAccountsForCaller(), account, getCallingUid());
     }
 
-    private boolean removeAccountInternal(UserAccounts accounts, Account account) {
+    private boolean removeAccountInternal(UserAccounts accounts, Account account, int callingUid) {
         int deleted;
         synchronized (accounts.cacheLock) {
             final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -1376,21 +1391,20 @@
 
             logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_ACCOUNTS, accountId, accounts);
         }
-        if (accounts.userId == UserHandle.USER_OWNER) {
-            // Owner's account was removed, remove from any users that are sharing
-            // this account.
-            int callingUid = getCallingUid();
-            long id = Binder.clearCallingIdentity();
-            try {
+        long id = Binder.clearCallingIdentity();
+        try {
+            int parentUserId = accounts.userId;
+            if (canHaveProfile(parentUserId)) {
+                // Remove from any restricted profiles that are sharing this account.
                 List<UserInfo> users = mUserManager.getUsers(true);
                 for (UserInfo user : users) {
-                    if (!user.isPrimary() && user.isRestricted()) {
+                    if (user.isRestricted() && parentUserId == (user.restrictedProfileParentId)) {
                         removeSharedAccountAsUser(account, user.id, callingUid);
                     }
                 }
-            } finally {
-                Binder.restoreCallingIdentity(id);
             }
+        } finally {
+            Binder.restoreCallingIdentity(id);
         }
         return (deleted > 0);
     }
@@ -2707,7 +2721,7 @@
         if (r > 0) {
             logRecord(db, DebugDbHelper.ACTION_ACCOUNT_REMOVE, TABLE_SHARED_ACCOUNTS,
                     sharedTableAccountId, accounts, callingUid);
-            removeAccountInternal(accounts, account);
+            removeAccountInternal(accounts, account, callingUid);
         }
         return r > 0;
     }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0119000..4949138 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2085,7 +2085,8 @@
     }
 
     private boolean collectPackageServicesLocked(String packageName, Set<String> filterByClasses,
-            boolean evenPersistent, boolean doit, ArrayMap<ComponentName, ServiceRecord> services) {
+            boolean evenPersistent, boolean doit, boolean killProcess,
+            ArrayMap<ComponentName, ServiceRecord> services) {
         boolean didSomething = false;
         for (int i = services.size() - 1; i >= 0; i--) {
             ServiceRecord service = services.valueAt(i);
@@ -2101,7 +2102,7 @@
                 didSomething = true;
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null) {
-                    service.app.removed = true;
+                    service.app.removed = killProcess;
                     if (!service.app.persistent) {
                         service.app.services.remove(service);
                     }
@@ -2118,7 +2119,7 @@
     }
 
     boolean bringDownDisabledPackageServicesLocked(String packageName, Set<String> filterByClasses,
-            int userId, boolean evenPersistent, boolean doit) {
+            int userId, boolean evenPersistent, boolean killProcess, boolean doit) {
         boolean didSomething = false;
 
         if (mTmpCollectionResults != null) {
@@ -2128,7 +2129,7 @@
         if (userId == UserHandle.USER_ALL) {
             for (int i = mServiceMap.size() - 1; i >= 0; i--) {
                 didSomething |= collectPackageServicesLocked(packageName, filterByClasses,
-                        evenPersistent, doit, mServiceMap.valueAt(i).mServicesByName);
+                        evenPersistent, doit, killProcess, mServiceMap.valueAt(i).mServicesByName);
                 if (!doit && didSomething) {
                     return true;
                 }
@@ -2138,7 +2139,7 @@
             if (smap != null) {
                 ArrayMap<ComponentName, ServiceRecord> items = smap.mServicesByName;
                 didSomething = collectPackageServicesLocked(packageName, filterByClasses,
-                        evenPersistent, doit, items);
+                        evenPersistent, doit, killProcess, items);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8e24127..81936ee 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
 import static android.app.ActivityManager.INVALID_STACK_ID;
@@ -214,6 +215,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UpdateLock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -405,6 +407,17 @@
     private static final int PERSISTENT_MASK =
             ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT;
 
+
+    // Delay to disable app launch boost
+    static final int APP_BOOST_MESSAGE_DELAY = 3000;
+    // Lower delay than APP_BOOST_MESSAGE_DELAY to disable the boost
+    static final int APP_BOOST_TIMEOUT = 2500;
+
+    private static native int nativeMigrateToBoost();
+    private static native int nativeMigrateFromBoost();
+    private boolean mIsBoosted = false;
+    private long mBoostStartTime = 0;
+
     /** All system services */
     SystemServiceManager mSystemServiceManager;
 
@@ -1366,6 +1379,7 @@
     static final int REPORT_TIME_TRACKER_MSG = 55;
     static final int REPORT_USER_SWITCH_COMPLETE_MSG = 56;
     static final int SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG = 57;
+    static final int APP_BOOST_DEACTIVATE_MSG = 58;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1884,7 +1898,9 @@
             }
             case FINISH_BOOTING_MSG: {
                 if (msg.arg1 != 0) {
+                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
                     finishBooting();
+                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 }
                 if (msg.arg2 != 0) {
                     enableScreenAfterBoot();
@@ -2044,6 +2060,20 @@
                 // it is finished we make sure it is reset to its default.
                 mUserIsMonkey = false;
             } break;
+            case APP_BOOST_DEACTIVATE_MSG : {
+                synchronized(ActivityManagerService.this) {
+                    if (mIsBoosted) {
+                        if (mBoostStartTime < (SystemClock.uptimeMillis() - APP_BOOST_TIMEOUT)) {
+                            nativeMigrateFromBoost();
+                            mIsBoosted = false;
+                            mBoostStartTime = 0;
+                        } else {
+                            Message newmsg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+                            mHandler.sendMessageDelayed(newmsg, APP_BOOST_TIMEOUT);
+                        }
+                    }
+                }
+            } break;
             }
         }
     };
@@ -2700,6 +2730,40 @@
         }
     }
 
+    /**
+     * Activate an activity by bringing it to the top and set the focus on it.
+     * Note: This is only allowed for activities which are on the freeform stack.
+     * @param token The token of the activity calling which will get activated.
+     */
+    @Override
+    public void activateActivity(IBinder token) {
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "ActivateActivity token=" + token);
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            synchronized (ActivityManagerService.this) {
+                final ActivityRecord anyTaskRecord = ActivityRecord.isInStackLocked(token);
+                if (anyTaskRecord == null) {
+                    Slog.w(TAG, "ActivateActivity: token=" + token + " not found");
+                    return;
+                }
+                TaskRecord task = anyTaskRecord.task;
+                final boolean runsOnFreeformStack =
+                        task.stack.getStackId() == FREEFORM_WORKSPACE_STACK_ID;
+                if (!runsOnFreeformStack) {
+                    Slog.w(TAG, "Tried to use activateActivity on a non freeform workspace!");
+                } else if (task != null) {
+                    ActivityRecord topTaskRecord = task.topRunningActivityLocked(null);
+                    if (topTaskRecord != null) {
+                        setFocusedActivityLocked(topTaskRecord, "activateActivity");
+                        mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+                    }
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     @Override
     public void setFocusedTask(int taskId) {
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedTask: taskId=" + taskId);
@@ -3142,6 +3206,16 @@
             app = null;
         }
 
+        // app launch boost for big.little configurations
+        // use cpusets to migrate freshly launched tasks to big cores
+        synchronized(ActivityManagerService.this) {
+            nativeMigrateToBoost();
+            mIsBoosted = true;
+            mBoostStartTime = SystemClock.uptimeMillis();
+            Message msg = mHandler.obtainMessage(APP_BOOST_DEACTIVATE_MSG);
+            mHandler.sendMessageDelayed(msg, APP_BOOST_MESSAGE_DELAY);
+        }
+
         // We don't have to do anything more if:
         // (1) There is an existing application record; and
         // (2) The caller doesn't think it is dead, OR there is no thread
@@ -4151,7 +4225,7 @@
                 throw new IllegalArgumentException("Task " + taskId + " not found.");
             }
             if (task.getRootActivity() != null) {
-                moveTaskToFrontLocked(task.taskId, 0, null);
+                moveTaskToFrontLocked(task.taskId, 0, options);
                 return ActivityManager.START_TASK_TO_FRONT;
             }
             callingUid = task.mCallingUid;
@@ -5573,7 +5647,7 @@
     }
 
     private void cleanupDisabledPackageComponentsLocked(
-            String packageName, int userId, String[] changedClasses) {
+            String packageName, int userId, boolean killProcess, String[] changedClasses) {
 
         Set<String> disabledClasses = null;
         boolean packageDisabled = false;
@@ -5643,7 +5717,7 @@
 
         // Clean-up disabled services.
         mServices.bringDownDisabledPackageServicesLocked(
-                packageName, disabledClasses, userId, false, true);
+                packageName, disabledClasses, userId, false, killProcess, true);
 
         // Clean-up disabled providers.
         ArrayList<ContentProviderRecord> providers = new ArrayList<>();
@@ -5728,7 +5802,7 @@
         }
 
         if (mServices.bringDownDisabledPackageServicesLocked(
-                packageName, null, userId, evenPersistent, doit)) {
+                packageName, null, userId, evenPersistent, true, doit)) {
             if (!doit) {
                 return true;
             }
@@ -6415,7 +6489,9 @@
             mBootAnimationComplete = true;
         }
         if (callFinishBooting) {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
             finishBooting();
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
@@ -6430,7 +6506,9 @@
         }
 
         if (booting) {
+            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");
             finishBooting();
+            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
         }
 
         if (enableScreen) {
@@ -16814,7 +16892,9 @@
                                 boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
                                 boolean fullUninstall = removed &&
                                         !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
-                                if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
+                                final boolean killProcess =
+                                        !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
+                                if (killProcess) {
                                     forceStopPackageLocked(ssp, UserHandle.getAppId(
                                             intent.getIntExtra(Intent.EXTRA_UID, -1)),
                                             false, true, true, false, fullUninstall, userId,
@@ -16834,7 +16914,7 @@
                                         mBatteryStatsService.notePackageUninstalled(ssp);
                                     }
                                 } else {
-                                    cleanupDisabledPackageComponentsLocked(ssp, userId,
+                                    cleanupDisabledPackageComponentsLocked(ssp, userId, killProcess,
                                             intent.getStringArrayExtra(
                                                     Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
                                 }
@@ -17376,8 +17456,10 @@
         }
 
         // Can't call out of the system process with a lock held, so post a message.
-        mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
-                app.instrumentationUiAutomationConnection).sendToTarget();
+        if (app.instrumentationUiAutomationConnection != null) {
+            mHandler.obtainMessage(SHUTDOWN_UI_AUTOMATION_CONNECTION_MSG,
+                    app.instrumentationUiAutomationConnection).sendToTarget();
+        }
 
         app.instrumentationWatcher = null;
         app.instrumentationUiAutomationConnection = null;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index f50df3a..751acb6 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -18,7 +18,6 @@
 
 import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 
@@ -391,7 +390,9 @@
 
     void setBounds(Rect bounds) {
         mBounds = mFullscreen ? null : new Rect(bounds);
-        mTaskPositioner.configure(bounds);
+        if (mTaskPositioner != null) {
+            mTaskPositioner.configure(bounds);
+        }
     }
 
     boolean okToShowLocked(ActivityRecord r) {
@@ -3975,8 +3976,7 @@
      * for whatever reason.  Ensures the HistoryRecord is updated with the
      * correct configuration and all other bookkeeping is handled.
      */
-    final boolean ensureActivityConfigurationLocked(ActivityRecord r,
-            int globalChanges) {
+    final boolean ensureActivityConfigurationLocked(ActivityRecord r, int globalChanges) {
         if (mConfigWillChange) {
             if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION,
                     "Skipping config check (will change): " + r);
@@ -4549,10 +4549,11 @@
             boolean toTop) {
         TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
                 voiceInteractor);
+        // add the task to stack first, mTaskPositioner might need the stack association
+        addTask(task, toTop, false);
         if (mTaskPositioner != null) {
             mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout);
         }
-        addTask(task, toTop, false);
         return task;
     }
 
@@ -4589,25 +4590,20 @@
 
     void addConfigOverride(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
-                        r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                        (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                        r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
-                        bounds);
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        task.updateOverrideConfiguration(bounds);
+        mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
+                r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
+                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
+                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
+                bounds, task.mOverrideConfig);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
         final Rect bounds = task.getLaunchBounds();
-        final Configuration config =
-                mWindowManager.setAppTask(r.appToken, task.taskId, task.getLaunchBounds());
-        if (config != null) {
-            task.updateOverrideConfiguration(config, bounds);
-        }
+        task.updateOverrideConfiguration(bounds);
+        mWindowManager.setAppTask(
+                r.appToken, task.taskId, task.getLaunchBounds(), task.mOverrideConfig);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index c86056b..b7c55d4 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -334,6 +333,9 @@
     // temp. rect used during resize calculation so we don't need to create a new object each time.
     private final Rect tempRect = new Rect();
 
+    private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
+    private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+
     /**
      * Description of a request to start a new activity, which has been held
      * due to app switches being disabled.
@@ -1762,7 +1764,7 @@
         return ACTIVITY_RESTRICTION_NONE;
     }
 
-    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask) {
+    ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds) {
         final TaskRecord task = r.task;
 
         // On leanback only devices we should keep all activities in the same stack.
@@ -1813,10 +1815,10 @@
             }
 
             // If there is no suitable dynamic stack then we figure out which static stack to use.
-            stack = getStack(
-                    task != null
-                            ? task.getLaunchStackId(mFocusedStack) : FULLSCREEN_WORKSPACE_STACK_ID,
-                    CREATE_IF_NEEDED, ON_TOP);
+            int stackId = task != null ? task.getLaunchStackId() :
+                        bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
+                                         FULLSCREEN_WORKSPACE_STACK_ID;
+            stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, "computeStackFocus: New stack r="
                     + r + " stackId=" + stack.mStackId);
             return stack;
@@ -1844,6 +1846,22 @@
         final Intent intent = r.intent;
         final int callingUid = r.launchedFromUid;
 
+        boolean overrideBounds = false;
+        Rect newBounds = null;
+        if (r.info.resizeable || (inTask != null && inTask.mResizeable)) {
+            if (intent.hasExtra(ActivityOptions.KEY_BOUNDS)) {
+                overrideBounds = true;
+                newBounds = Rect.unflattenFromString(
+                        intent.getStringExtra(ActivityOptions.KEY_BOUNDS));
+            } else if (options != null) {
+                ActivityOptions opts = new ActivityOptions(options);
+                if (opts.hasBounds()) {
+                    overrideBounds = true;
+                    newBounds = opts.getBounds();
+                }
+            }
+        }
+
         // In some flows in to this function, we retrieve the task record and hold on to it
         // without a lock before calling back in to here...  so the task at this point may
         // not actually be in recents.  Check for that, and if it isn't in recents just
@@ -2197,7 +2215,8 @@
                             if (task != null && task.stack == null) {
                                 // Target stack got cleared when we all activities were removed
                                 // above. Go ahead and reset it.
-                                targetStack = computeStackFocus(sourceRecord, false /* newTask */);
+                                targetStack = computeStackFocus(
+                                        sourceRecord, false /* newTask */, null /* bounds */);
                                 targetStack.addTask(
                                         task, !launchTaskBehind /* toTop */, false /* moving */);
                             }
@@ -2323,7 +2342,7 @@
         if (r.resultTo == null && inTask == null && !addingToTask
                 && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
             newTask = true;
-            targetStack = computeStackFocus(r, newTask);
+            targetStack = computeStackFocus(r, newTask, newBounds);
             if (doResume) {
                 targetStack.moveToFront("startingNewTask");
             }
@@ -2334,6 +2353,9 @@
                         newTaskIntent != null ? newTaskIntent : intent,
                         voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
                         taskToAffiliate);
+                if (overrideBounds) {
+                    r.task.updateOverrideConfiguration(newBounds);
+                }
                 if (DEBUG_TASKS) Slog.v(TAG_TASKS,
                         "Starting new activity " + r + " in new task " + r.task);
             } else {
@@ -2418,6 +2440,14 @@
                 Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
                 return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
             }
+            if (overrideBounds) {
+                inTask.updateOverrideConfiguration(newBounds);
+                int stackId = inTask.getLaunchStackId();
+                if (stackId != inTask.stack.mStackId) {
+                    moveTaskToStackUncheckedLocked(
+                            inTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+                }
+            }
             targetStack = inTask.stack;
             targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, r.appTimeTracker,
                     "inTaskToFront");
@@ -2455,7 +2485,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 = computeStackFocus(r, newTask);
+            targetStack = computeStackFocus(r, newTask, null /* bounds */);
             if (doResume) {
                 targetStack.moveToFront("addingToTopTask");
             }
@@ -2814,9 +2844,26 @@
                     + task + " to front. Stack is null");
             return;
         }
-        task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+
+        int stackId = task.stack.mStackId;
+        if (task.mResizeable && options != null) {
+            ActivityOptions opts = new ActivityOptions(options);
+            if (opts.hasBounds()) {
+                Rect bounds = opts.getBounds();
+                task.updateOverrideConfiguration(bounds);
+                mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, false);
+                stackId = task.getLaunchStackId();
+            }
+        }
+
+        if (stackId != task.stack.mStackId) {
+            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, FORCE_FOCUS, reason);
+        } else {
+            task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
                 task.getTopActivity() == null ? null : task.getTopActivity().appTimeTracker,
                 reason);
+        }
+
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
@@ -2917,19 +2964,19 @@
         ActivityRecord r = stack.topRunningActivityLocked(null);
         final boolean resizeTasks = r != null && r.task.mResizeable;
 
-        final IntArray changedTaskIds = new IntArray(stack.numTasks());
-        final List<Configuration> newTaskConfigs = new ArrayList<>(stack.numTasks());
-        stack.mFullscreen = mWindowManager.resizeStack(
-                stackId, bounds, resizeTasks, changedTaskIds, newTaskConfigs);
-        for (int i = changedTaskIds.size() - 1; i >= 0; i--) {
-            final TaskRecord task = anyTaskForIdLocked(changedTaskIds.get(i), false);
-            if (task == null) {
-                Slog.wtf(TAG, "Task in WindowManager, but not in ActivityManager???");
-                continue;
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        if (resizeTasks) {
+            ArrayList<TaskRecord> tasks = stack.getAllTasks();
+            for (int i = tasks.size() - 1; i >= 0; i--) {
+                TaskRecord task = tasks.get(i);
+                task.updateOverrideConfiguration(bounds);
+                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+                mTmpBounds.put(task.taskId, task.mBounds);
             }
-            task.updateOverrideConfiguration(newTaskConfigs.get(i), bounds);
         }
-
+        stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, resizeTasks, mTmpConfigs,
+                mTmpBounds);
         if (stack.mStackId == DOCKED_STACK_ID) {
             // Dock stack funness...Yay!
             if (stack.mFullscreen) {
@@ -3005,7 +3052,7 @@
             // Task doesn't exist in window manager yet (e.g. was restored from recents).
             // All we can do for now is update the bounds so it can be used when the task is
             // added to window manager.
-            task.mBounds = task.mLastNonFullscreenBounds = new Rect(bounds);
+            task.updateOverrideConfiguration(bounds);
             if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
                 // re-restore the task so it can have the proper stack association.
                 restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
@@ -3024,25 +3071,33 @@
             stackId = FREEFORM_WORKSPACE_STACK_ID;
         }
         if (stackId != task.stack.mStackId) {
-            final String reason = "resizeTask";
-            final ActivityStack stack =
-                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
+            moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
         }
 
-        final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
-        if (task.updateOverrideConfiguration(overrideConfig, bounds)) {
+        final Configuration overrideConfig =  task.updateOverrideConfiguration(bounds);
+        // This variable holds information whether the configuration didn't change in a signficant
+        // way and the activity was kept the way it was. If it's false, it means the activity had
+        // to be relaunched due to configuration change.
+        boolean kept = true;
+        if (overrideConfig != null) {
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
-                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
+                kept = stack.ensureActivityConfigurationLocked(r, 0);
+                // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0);
-                if (!updated) {
+                if (!kept) {
                     resumeTopActivitiesLocked(stack, null, null);
+                    // We are about to relaunch the activity because its configuration changed due
+                    // to size change. The activity will first remove the old window and then add a
+                    // new one. This call will tell window manager about this, so it can preserve
+                    // the old window until the new one is drawn. This prevents having a gap between
+                    // the removal and addition, in which no window is visible.
+                    mWindowManager.setReplacingWindow(r.appToken);
                 }
             }
         }
+        mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept);
     }
 
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
@@ -3077,8 +3132,7 @@
      */
     private boolean restoreRecentTaskLocked(TaskRecord task, int stackId) {
         if (stackId == INVALID_STACK_ID) {
-            stackId = mLeanbackOnlyDevice ?
-                    mHomeStack.mStackId : task.getLaunchStackId(mFocusedStack);
+            stackId = mLeanbackOnlyDevice ? mHomeStack.mStackId : task.getLaunchStackId();
         }
         if (task.stack != null) {
             // Task has already been restored once. See if we need to do anything more
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a956c56..960cbf1 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -509,7 +509,7 @@
                     break;
                 }
                 int appOp = AppOpsManager.permissionToOpCode(requiredPermission);
-                if (appOp != r.appOp
+                if (appOp != AppOpsManager.OP_NONE && appOp != r.appOp
                         && mService.mAppOpsService.noteOperation(appOp,
                         filter.receiverList.uid, filter.packageName)
                         != AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 5c4fd13..3d45915 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -234,7 +234,7 @@
                 break;
             }
         }
-        task.setInitialBounds(proposal);
+        task.updateOverrideConfiguration(proposal);
     }
 
     private boolean shiftedToFar(Rect start, int shiftPolicy) {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9cbaec5..5694e704 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,6 +52,7 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.service.voice.IVoiceInteractionSession;
+import android.util.DisplayMetrics;
 import android.util.Slog;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.util.XmlUtils;
@@ -63,6 +64,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Objects;
 
 final class TaskRecord {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
@@ -106,6 +108,13 @@
 
     static final int INVALID_TASK_ID = -1;
 
+    // The height/width divide used when fitting a task within a bounds with method
+    // {@link #fitWithinBounds}.
+    // We always want the task to to be visible in the bounds without affecting its size when
+    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
+    // the input bounds right or bottom side minus the width or height divided by this value.
+    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
+
     final int taskId;       // Unique identifier for this task.
     String affinity;        // The affinity name for this task, or null; may change identity.
     String rootAffinity;    // Initial base affinity, or null; does not change from initial root.
@@ -271,8 +280,7 @@
             long _firstActiveTime, long _lastActiveTime, long lastTimeMoved,
             boolean neverRelinquishIdentity, TaskDescription _lastTaskDescription,
             int taskAffiliation, int prevTaskId, int nextTaskId, int taskAffiliationColor,
-            int callingUid, String callingPackage, boolean resizeable, boolean privileged,
-            Rect bounds) {
+            int callingUid, String callingPackage, boolean resizeable, boolean privileged) {
         mService = service;
         mFilename = String.valueOf(_taskId) + TASK_THUMBNAIL_SUFFIX +
                 TaskPersister.IMAGE_EXTENSION;
@@ -309,7 +317,6 @@
         mCallingPackage = callingPackage;
         mResizeable = resizeable;
         mPrivileged = privileged;
-        mBounds = mLastNonFullscreenBounds = bounds;
     }
 
     void touchActiveTime() {
@@ -1163,7 +1170,8 @@
                 autoRemoveRecents, askedCompatMode, taskType, userId, effectiveUid, lastDescription,
                 activities, firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
                 taskDescription, taskAffiliation, prevTaskId, nextTaskId, taskAffiliationColor,
-                callingUid, callingPackage, resizeable, privileged, bounds);
+                callingUid, callingPackage, resizeable, privileged);
+        task.updateOverrideConfiguration(bounds);
 
         for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
             activities.get(activityNdx).task = task;
@@ -1173,41 +1181,63 @@
         return task;
     }
 
-    boolean updateOverrideConfiguration(Configuration newConfig, Rect bounds) {
+    /**
+     * Update task's override configuration based on the bounds.
+     * @return Update configuration or null if there is no change.
+     */
+    Configuration updateOverrideConfiguration(Rect bounds) {
+        if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+            // For freeform stack we don't adjust the size of the tasks to match that of the
+            // stack, but we do try to make sure the tasks are still contained with the
+            // bounds of the stack.
+            fitWithinBounds(bounds, stack.mBounds);
+        }
+        if (Objects.equals(mBounds, bounds)) {
+            return null;
+        }
         Configuration oldConfig = mOverrideConfig;
-        mOverrideConfig = (newConfig == null) ? Configuration.EMPTY : newConfig;
-        // We override the configuration only when the task's dimensions are different from the
-        // display. In this manner, we know that if the override configuration is empty, the task
-        // is necessarily fullscreen.
-        mFullscreen = Configuration.EMPTY.equals(mOverrideConfig);
+
+        mFullscreen = bounds == null;
         if (mFullscreen) {
             if (mBounds != null && stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mBounds = null;
+            mOverrideConfig = Configuration.EMPTY;
         } else {
             mBounds = new Rect(bounds);
             if (stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
+
+            final Configuration serviceConfig = mService.mConfiguration;
+            mOverrideConfig = new Configuration(serviceConfig);
+            // TODO(multidisplay): Update Dp to that of display stack is on.
+            final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            mOverrideConfig.screenWidthDp =
+                    Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
+            mOverrideConfig.screenHeightDp =
+                    Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
+            mOverrideConfig.smallestScreenWidthDp =
+                    Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
+            mOverrideConfig.orientation =
+                    (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
+                            ? Configuration.ORIENTATION_PORTRAIT
+                            : Configuration.ORIENTATION_LANDSCAPE;
         }
-        return !mOverrideConfig.equals(oldConfig);
+        return !mOverrideConfig.equals(oldConfig) ? mOverrideConfig : null;
     }
 
-    /** Returns the stack that should be used to launch this task. */
-    int getLaunchStackId(ActivityStack focusStack) {
-        if (stack != null) {
-            // We are already in a stack silly...
-            return stack.mStackId;
-        }
-        if (isHomeTask()) {
+    /**
+     * Returns the correct stack to use based on task type and currently set bounds,
+     * regardless of the focused stack and current stack association of the task.
+     * The task will be moved (and stack focus changed) later if necessary.
+     */
+    int getLaunchStackId() {
+        if (!isApplicationTask()) {
             return HOME_STACK_ID;
         }
-        if (focusStack != null && focusStack.mStackId != HOME_STACK_ID) {
-            // Like it or not you are going in the focused stack!
-            return focusStack.mStackId;
-        }
-        if (mBounds != null || mLastNonFullscreenBounds != null) {
+        if (mBounds != null) {
             return FREEFORM_WORKSPACE_STACK_ID;
         }
         return FULLSCREEN_WORKSPACE_STACK_ID;
@@ -1225,12 +1255,43 @@
         return mLastNonFullscreenBounds;
     }
 
-    void setInitialBounds(Rect rect) {
-        if (mBounds == null) {
-            mBounds = new Rect();
+    /**
+     * Adjust bounds to stay within stack bounds.
+     *
+     * Since bounds might be outside of stack bounds, this method tries to move the bounds in a way
+     * that keep them unchanged, but be contained within the stack bounds.
+     *
+     * @param bounds Bounds to be adjusted.
+     * @param stackBounds Bounds within which the other bounds should remain.
+     */
+    private static void fitWithinBounds(Rect bounds, Rect stackBounds) {
+        if (stackBounds == null || stackBounds.contains(bounds)) {
+            return;
         }
-        mBounds.set(rect);
-        mLastNonFullscreenBounds = mBounds;
+
+        if (bounds.left < stackBounds.left || bounds.right > stackBounds.right) {
+            final int maxRight = stackBounds.right
+                    - (stackBounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int horizontalDiff = stackBounds.left - bounds.left;
+            if ((horizontalDiff < 0 && bounds.left >= maxRight)
+                    || (bounds.left + horizontalDiff >= maxRight)) {
+                horizontalDiff = maxRight - bounds.left;
+            }
+            bounds.left += horizontalDiff;
+            bounds.right += horizontalDiff;
+        }
+
+        if (bounds.top < stackBounds.top || bounds.bottom > stackBounds.bottom) {
+            final int maxBottom = stackBounds.bottom
+                    - (stackBounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
+            int verticalDiff = stackBounds.top - bounds.top;
+            if ((verticalDiff < 0 && bounds.top >= maxBottom)
+                    || (bounds.top + verticalDiff >= maxBottom)) {
+                verticalDiff = maxBottom - bounds.top;
+            }
+            bounds.top += verticalDiff;
+            bounds.bottom += verticalDiff;
+        }
     }
 
     void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 470bd5a..0023258 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -18,13 +18,18 @@
 
 import android.Manifest;
 import android.app.ActivityManager;
+import android.app.ActivityManager.RunningAppProcessInfo;
+import android.app.ActivityManager.RunningTaskInfo;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
+import android.hardware.fingerprint.IFingerprintServiceLockoutResetCallback;
 import android.os.Binder;
+import android.os.DeadObjectException;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
@@ -51,8 +56,8 @@
 import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
-import android.view.Display;
 
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
 import static android.Manifest.permission.RESET_FINGERPRINT_LOCKOUT;
 import static android.Manifest.permission.USE_FINGERPRINT;
@@ -60,6 +65,7 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -83,12 +89,15 @@
     private ClientMonitor mAuthClient = null;
     private ClientMonitor mEnrollClient = null;
     private ClientMonitor mRemoveClient = null;
+    private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
+            new ArrayList<>();
     private final AppOpsManager mAppOps;
 
     private static final long MS_PER_SEC = 1000;
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
     private static final int MAX_FAILED_ATTEMPTS = 5;
     private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
+    private final String mKeyguardPackage;
 
     Handler mHandler = new Handler() {
         @Override
@@ -121,6 +130,8 @@
     public FingerprintService(Context context) {
         super(context);
         mContext = context;
+        mKeyguardPackage = ComponentName.unflattenFromString(context.getResources().getString(
+                com.android.internal.R.string.config_keyguardComponent)).getPackageName();
         mAppOps = context.getSystemService(AppOpsManager.class);
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
     }
@@ -129,7 +140,7 @@
     public void binderDied() {
         Slog.v(TAG, "fingerprintd died");
         mDaemon = null;
-        dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+        handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
     }
 
     public IFingerprintDaemon getFingerprintDaemon() {
@@ -157,7 +168,7 @@
         return mDaemon;
     }
 
-    protected void dispatchEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
+    protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
         if (fingerIds.length != groupIds.length) {
             Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
                     + fingerIds + ", g[]=" + groupIds);
@@ -167,7 +178,7 @@
         // TODO: update fingerprint/name pairs
     }
 
-    protected void dispatchRemoved(long deviceId, int fingerId, int groupId) {
+    protected void handleRemoved(long deviceId, int fingerId, int groupId) {
         final ClientMonitor client = mRemoveClient;
         if (fingerId != 0) {
             removeTemplateForUser(mRemoveClient, fingerId);
@@ -177,7 +188,7 @@
         }
     }
 
-    protected void dispatchError(long deviceId, int error) {
+    protected void handleError(long deviceId, int error) {
         if (mEnrollClient != null) {
             final IBinder token = mEnrollClient.token;
             if (mEnrollClient.sendError(error)) {
@@ -193,7 +204,7 @@
         }
     }
 
-    protected void dispatchAuthenticated(long deviceId, int fingerId, int groupId) {
+    protected void handleAuthenticated(long deviceId, int fingerId, int groupId) {
         if (mAuthClient != null) {
             final IBinder token = mAuthClient.token;
             if (mAuthClient.sendAuthenticated(fingerId, groupId)) {
@@ -203,7 +214,7 @@
         }
     }
 
-    protected void dispatchAcquired(long deviceId, int acquiredInfo) {
+    protected void handleAcquired(long deviceId, int acquiredInfo) {
         if (mEnrollClient != null) {
             if (mEnrollClient.sendAcquired(acquiredInfo)) {
                 removeClient(mEnrollClient);
@@ -215,16 +226,7 @@
         }
     }
 
-    private void userActivity() {
-        long now = SystemClock.uptimeMillis();
-        mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
-    }
-
-    void handleUserSwitching(int userId) {
-        updateActiveGroup(userId);
-    }
-
-    protected void dispatchEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
+    protected void handleEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
         if (mEnrollClient != null) {
             if (mEnrollClient.sendEnrollResult(fingerId, groupId, remaining)) {
                 if (remaining == 0) {
@@ -235,6 +237,15 @@
         }
     }
 
+    private void userActivity() {
+        long now = SystemClock.uptimeMillis();
+        mPowerManager.userActivity(now, PowerManager.USER_ACTIVITY_EVENT_TOUCH, 0);
+    }
+
+    void handleUserSwitching(int userId) {
+        updateActiveGroup(userId);
+    }
+
     private void removeClient(ClientMonitor client) {
         if (client == null) return;
         client.destroy();
@@ -248,7 +259,7 @@
     }
 
     private boolean inLockoutMode() {
-        return mFailedAttempts > MAX_FAILED_ATTEMPTS;
+        return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
     }
 
     private void resetFailedAttempts() {
@@ -259,11 +270,12 @@
         // If we're asked to reset failed attempts externally (i.e. from Keyguard), the runnable
         // may still be in the queue; remove it.
         mHandler.removeCallbacks(mLockoutReset);
+        notifyLockoutResetMonitors();
     }
 
     private boolean handleFailedAttempt(ClientMonitor clientMonitor) {
         mFailedAttempts++;
-        if (mFailedAttempts > MAX_FAILED_ATTEMPTS) {
+        if (inLockoutMode()) {
             // Failing multiple times will continue to push out the lockout time.
             mHandler.removeCallbacks(mLockoutReset);
             mHandler.postDelayed(mLockoutReset, FAIL_LOCKOUT_TIMEOUT_MS);
@@ -298,7 +310,7 @@
             final int result = daemon.enroll(cryptoToken, groupId, timeout);
             if (result != 0) {
                 Slog.w(TAG, "startEnroll failed, result=" + result);
-                dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startEnroll failed", e);
@@ -392,7 +404,7 @@
             final int result = daemon.authenticate(opId, groupId);
             if (result != 0) {
                 Slog.w(TAG, "startAuthentication failed, result=" + result);
-                dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startAuthentication failed", e);
@@ -442,7 +454,7 @@
             final int result = daemon.remove(fingerId, userId);
             if (result != 0) {
                 Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
-                dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startRemove failed", e);
@@ -493,10 +505,67 @@
         return false;
     }
 
-    private boolean canUseFingerprint(String opPackageName) {
+    private boolean isForegroundActivity(int uid, int pid) {
+        try {
+            List<RunningAppProcessInfo> procs =
+                    ActivityManagerNative.getDefault().getRunningAppProcesses();
+            int N = procs.size();
+            for (int i = 0; i < N; i++) {
+                RunningAppProcessInfo proc = procs.get(i);
+                if (proc.pid == pid && proc.uid == uid
+                        && proc.importance == IMPORTANCE_FOREGROUND) {
+                    return true;
+                }
+            }
+        } catch (RemoteException e) {
+            Slog.w(TAG, "am.getRunningAppProcesses() failed");
+        }
+        return false;
+    }
+
+    /**
+     * @param opPackageName name of package for caller
+     * @param foregroundOnly only allow this call while app is in the foreground
+     * @return true if caller can use fingerprint API
+     */
+    private boolean canUseFingerprint(String opPackageName, boolean foregroundOnly) {
         checkPermission(USE_FINGERPRINT);
-        return mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, Binder.getCallingUid(),
-                opPackageName) == AppOpsManager.MODE_ALLOWED;
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        if (opPackageName.equals(mKeyguardPackage)) {
+            return true; // Keyguard is always allowed
+        }
+        if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
+            Slog.w(TAG,"Rejecting " + opPackageName + " ; not a current user or profile");
+            return false;
+        }
+        if (mAppOps.noteOp(AppOpsManager.OP_USE_FINGERPRINT, uid, opPackageName)
+                != AppOpsManager.MODE_ALLOWED) {
+            Slog.v(TAG, "Rejecting " + opPackageName + " ; permission denied");
+            return false;
+        }
+        if (foregroundOnly && !isForegroundActivity(uid, pid)) {
+            Slog.v(TAG, "Rejecting " + opPackageName + " ; not in foreground");
+            return false;
+        }
+        return true;
+    }
+
+    private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
+        if (!mLockoutMonitors.contains(monitor)) {
+            mLockoutMonitors.add(monitor);
+        }
+    }
+
+    private void removeLockoutResetCallback(
+            FingerprintServiceLockoutResetMonitor monitor) {
+        mLockoutMonitors.remove(monitor);
+    }
+
+    private void notifyLockoutResetMonitors() {
+        for (int i = 0; i < mLockoutMonitors.size(); i++) {
+            mLockoutMonitors.get(i).sendLockoutReset();
+        }
     }
 
     private class ClientMonitor implements IBinder.DeathRecipient {
@@ -614,7 +683,7 @@
                     FingerprintUtils.vibrateFingerprintSuccess(getContext());
                 }
                 result |= true; // we have a valid fingerprint
-                mLockoutReset.run();
+                mHandler.post(mLockoutReset);
             }
             return result;
         }
@@ -654,36 +723,97 @@
         }
     }
 
+    private class FingerprintServiceLockoutResetMonitor {
+
+        private final IFingerprintServiceLockoutResetCallback mCallback;
+
+        public FingerprintServiceLockoutResetMonitor(
+                IFingerprintServiceLockoutResetCallback callback) {
+            mCallback = callback;
+        }
+
+        public void sendLockoutReset() {
+            if (mCallback != null) {
+                try {
+                    mCallback.onLockoutReset(mHalDeviceId);
+                } catch (DeadObjectException e) {
+                    Slog.w(TAG, "Death object while invoking onLockoutReset: ", e);
+                    mHandler.post(mRemoveCallbackRunnable);
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to invoke onLockoutReset: ", e);
+                }
+            }
+        }
+
+        private final Runnable mRemoveCallbackRunnable = new Runnable() {
+            @Override
+            public void run() {
+                removeLockoutResetCallback(FingerprintServiceLockoutResetMonitor.this);
+            }
+        };
+    }
+
     private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
 
         @Override
-        public void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining) {
-            dispatchEnrollResult(deviceId, fingerId, groupId, remaining);
+        public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
+                final int remaining) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleEnrollResult(deviceId, fingerId, groupId, remaining);
+                }
+            });
         }
 
         @Override
-        public void onAcquired(long deviceId, int acquiredInfo) {
-            dispatchAcquired(deviceId, acquiredInfo);
+        public void onAcquired(final long deviceId, final int acquiredInfo) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleAcquired(deviceId, acquiredInfo);
+                }
+            });
         }
 
         @Override
-        public void onAuthenticated(long deviceId, int fingerId, int groupId) {
-            dispatchAuthenticated(deviceId, fingerId, groupId);
+        public void onAuthenticated(final long deviceId, final int fingerId, final int groupId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleAuthenticated(deviceId, fingerId, groupId);
+                }
+            });
         }
 
         @Override
-        public void onError(long deviceId, int error) {
-            dispatchError(deviceId, error);
+        public void onError(final long deviceId, final int error) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleError(deviceId, error);
+                }
+            });
         }
 
         @Override
-        public void onRemoved(long deviceId, int fingerId, int groupId) {
-            dispatchRemoved(deviceId, fingerId, groupId);
+        public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleRemoved(deviceId, fingerId, groupId);
+                }
+            });
         }
 
         @Override
-        public void onEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
-            dispatchEnumerate(deviceId, fingerIds, groupIds);
+        public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    handleEnumerate(deviceId, fingerIds, groupIds);
+                }
+            });
         }
     };
 
@@ -751,12 +881,7 @@
         public void authenticate(final IBinder token, final long opId, final int groupId,
                 final IFingerprintServiceReceiver receiver, final int flags,
                 final String opPackageName) {
-            if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
-                Slog.w(TAG, "Can't authenticate non-current user");
-                return;
-            }
-            if (!canUseFingerprint(opPackageName)) {
-                Slog.w(TAG, "Calling not granted permission to use fingerprint");
+            if (!canUseFingerprint(opPackageName, true /* foregroundOnly */)) {
                 return;
             }
 
@@ -776,7 +901,7 @@
 
         @Override // Binder call
         public void cancelAuthentication(final IBinder token, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return;
             }
             mHandler.post(new Runnable() {
@@ -807,7 +932,7 @@
 
         @Override // Binder call
         public boolean isHardwareDetected(long deviceId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return false;
             }
             return mHalDeviceId != 0;
@@ -831,7 +956,7 @@
 
         @Override // Binder call
         public List<Fingerprint> getEnrolledFingerprints(int userId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return Collections.emptyList();
             }
             int effectiveUserId = getEffectiveUserId(userId);
@@ -841,7 +966,7 @@
 
         @Override // Binder call
         public boolean hasEnrolledFingerprints(int userId, String opPackageName) {
-            if (!canUseFingerprint(opPackageName)) {
+            if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return false;
             }
 
@@ -891,7 +1016,19 @@
         public void resetTimeout(byte [] token) {
             checkPermission(RESET_FINGERPRINT_LOCKOUT);
             // TODO: confirm security token when we move timeout management into the HAL layer.
-            mLockoutReset.run();
+            mHandler.post(mLockoutReset);
+        }
+
+        @Override
+        public void addLockoutResetCallback(final IFingerprintServiceLockoutResetCallback callback)
+                throws RemoteException {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    addLockoutResetMonitor(
+                            new FingerprintServiceLockoutResetMonitor(callback));
+                }
+            });
         }
     }
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 17b4f9c..5a13672 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -17,6 +17,7 @@
 package com.android.server.input;
 
 import android.view.Display;
+import com.android.internal.os.SomeArgs;
 import com.android.internal.R;
 import com.android.internal.util.XmlUtils;
 import com.android.server.DisplayThread;
@@ -52,6 +53,7 @@
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
 import android.hardware.input.InputManagerInternal;
+import android.hardware.input.ITabletModeChangedListener;
 import android.hardware.input.KeyboardLayout;
 import android.hardware.input.TouchCalibration;
 import android.os.Binder;
@@ -93,6 +95,7 @@
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 
 import libcore.io.Streams;
 import libcore.util.Objects;
@@ -112,6 +115,7 @@
     private static final int MSG_RELOAD_KEYBOARD_LAYOUTS = 3;
     private static final int MSG_UPDATE_KEYBOARD_LAYOUTS = 4;
     private static final int MSG_RELOAD_DEVICE_ALIASES = 5;
+    private static final int MSG_DELIVER_TABLET_MODE_CHANGED = 6;
 
     // Pointer to native input manager service object.
     private final long mPtr;
@@ -124,6 +128,13 @@
     private boolean mSystemReady;
     private NotificationManager mNotificationManager;
 
+    private final Object mTabletModeLock = new Object();
+    // List of currently registered tablet mode changed listeners by process id
+    private final SparseArray<TabletModeChangedListenerRecord> mTabletModeChangedListeners =
+            new SparseArray<>(); // guarded by mTabletModeLock
+    private final List<TabletModeChangedListenerRecord> mTempTabletModeChangedListenersToNotify =
+            new ArrayList<>();
+
     // Persistent data store.  Must be locked each time during use.
     private final PersistentDataStore mDataStore = new PersistentDataStore();
 
@@ -227,6 +238,11 @@
     /** Switch code: Lid switch.  When set, lid is shut. */
     public static final int SW_LID = 0x00;
 
+    /** Switch code: Tablet mode switch.
+     * When set, the device is in tablet mode (i.e. no keyboard is connected).
+     */
+    public static final int SW_TABLET_MODE = 0x01;
+
     /** Switch code: Keypad slide.  When set, keyboard is exposed. */
     public static final int SW_KEYPAD_SLIDE = 0x0a;
 
@@ -246,6 +262,7 @@
     public static final int SW_CAMERA_LENS_COVER = 0x09;
 
     public static final int SW_LID_BIT = 1 << SW_LID;
+    public static final int SW_TABLET_MODE_BIT = 1 << SW_TABLET_MODE;
     public static final int SW_KEYPAD_SLIDE_BIT = 1 << SW_KEYPAD_SLIDE;
     public static final int SW_HEADPHONE_INSERT_BIT = 1 << SW_HEADPHONE_INSERT;
     public static final int SW_MICROPHONE_INSERT_BIT = 1 << SW_MICROPHONE_INSERT;
@@ -774,6 +791,57 @@
         }
     }
 
+    @Override // Binder call
+    public void registerTabletModeChangedListener(ITabletModeChangedListener listener) {
+        if (!checkCallingPermission(android.Manifest.permission.TABLET_MODE_LISTENER,
+                "registerTabletModeChangedListener()")) {
+            throw new SecurityException("Requires TABLET_MODE_LISTENER permission");
+        }
+        if (listener == null) {
+            throw new IllegalArgumentException("listener must not be null");
+        }
+
+        synchronized (mTabletModeLock) {
+            final int callingPid = Binder.getCallingPid();
+            if (mTabletModeChangedListeners.get(callingPid) != null) {
+                throw new IllegalStateException("The calling process has already registered "
+                        + "a TabletModeChangedListener.");
+            }
+            TabletModeChangedListenerRecord record =
+                    new TabletModeChangedListenerRecord(callingPid, listener);
+            try {
+                IBinder binder = listener.asBinder();
+                binder.linkToDeath(record, 0);
+            } catch (RemoteException ex) {
+                throw new RuntimeException(ex);
+            }
+            mTabletModeChangedListeners.put(callingPid, record);
+        }
+    }
+
+    private void onTabletModeChangedListenerDied(int pid) {
+        synchronized (mTabletModeLock) {
+            mTabletModeChangedListeners.remove(pid);
+        }
+    }
+
+    // Must be called on handler
+    private void deliverTabletModeChanged(long whenNanos, boolean inTabletMode) {
+        mTempTabletModeChangedListenersToNotify.clear();
+        final int numListeners;
+        synchronized (mTabletModeLock) {
+            numListeners = mTabletModeChangedListeners.size();
+            for (int i = 0; i < numListeners; i++) {
+                mTempTabletModeChangedListenersToNotify.add(
+                        mTabletModeChangedListeners.valueAt(i));
+            }
+        }
+        for (int i = 0; i < numListeners; i++) {
+            mTempTabletModeChangedListenersToNotify.get(i).notifyTabletModeChanged(
+                    whenNanos, inTabletMode);
+        }
+    }
+
     // Must be called on handler.
     private void showMissingKeyboardLayoutNotification(InputDevice device) {
         if (!mKeyboardLayoutNotificationShown) {
@@ -1419,6 +1487,15 @@
             mWiredAccessoryCallbacks.notifyWiredAccessoryChanged(whenNanos, switchValues,
                     switchMask);
         }
+
+        if ((switchMask & SW_TABLET_MODE) != 0) {
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = (int) (whenNanos & 0xFFFFFFFF);
+            args.argi2 = (int) (whenNanos >> 32);
+            args.arg1 = Boolean.valueOf((switchValues & SW_TABLET_MODE_BIT) != 0);
+            mHandler.obtainMessage(MSG_DELIVER_TABLET_MODE_CHANGED,
+                    args).sendToTarget();
+        }
     }
 
     // Native callback.
@@ -1664,6 +1741,12 @@
                 case MSG_RELOAD_DEVICE_ALIASES:
                     reloadDeviceAliases();
                     break;
+                case MSG_DELIVER_TABLET_MODE_CHANGED:
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    long whenNanos = (args.argi1 & 0xFFFFFFFFl) | ((long) args.argi2 << 32);
+                    boolean inTabletMode = (boolean) args.arg1;
+                    deliverTabletModeChanged(whenNanos, inTabletMode);
+                    break;
             }
         }
     }
@@ -1755,6 +1838,34 @@
         }
     }
 
+    private final class TabletModeChangedListenerRecord implements DeathRecipient {
+        private final int mPid;
+        private final ITabletModeChangedListener mListener;
+
+        public TabletModeChangedListenerRecord(int pid, ITabletModeChangedListener listener) {
+            mPid = pid;
+            mListener = listener;
+        }
+
+        @Override
+        public void binderDied() {
+            if (DEBUG) {
+                Slog.d(TAG, "Tablet mode changed listener for pid " + mPid + " died.");
+            }
+            onTabletModeChangedListenerDied(mPid);
+        }
+
+        public void notifyTabletModeChanged(long whenNanos, boolean inTabletMode) {
+            try {
+                mListener.onTabletModeChanged(whenNanos, inTabletMode);
+            } catch (RemoteException ex) {
+                Slog.w(TAG, "Failed to notify process " + mPid +
+                        " that tablet mode changed, assuming it died.", ex);
+                binderDied();
+            }
+        }
+    }
+
     private final class VibratorToken implements DeathRecipient {
         public final int mDeviceId;
         public final IBinder mToken;
diff --git a/services/core/java/com/android/server/location/FlpHardwareProvider.java b/services/core/java/com/android/server/location/FlpHardwareProvider.java
index d4f3c4d..6d08c36 100644
--- a/services/core/java/com/android/server/location/FlpHardwareProvider.java
+++ b/services/core/java/com/android/server/location/FlpHardwareProvider.java
@@ -16,19 +16,18 @@
 
 package com.android.server.location;
 
+import android.content.Context;
 import android.hardware.location.GeofenceHardware;
 import android.hardware.location.GeofenceHardwareImpl;
 import android.hardware.location.GeofenceHardwareRequestParcelable;
 import android.hardware.location.IFusedLocationHardware;
 import android.hardware.location.IFusedLocationHardwareSink;
-import android.location.IFusedGeofenceHardware;
 import android.location.FusedBatchOptions;
+import android.location.IFusedGeofenceHardware;
 import android.location.Location;
 import android.location.LocationListener;
 import android.location.LocationManager;
 import android.location.LocationRequest;
-
-import android.content.Context;
 import android.os.Bundle;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -301,7 +300,6 @@
     private native void nativeRequestBatchedLocation(int lastNLocations);
     private native void nativeFlushBatchedLocations();
     private native void nativeInjectLocation(Location location);
-    // TODO [Fix] sort out the lifetime of the instance
     private native void nativeCleanup();
 
     // FlpDiagnosticsInterface members
@@ -341,6 +339,11 @@
         return mGeofenceHardwareService;
     }
 
+    public void cleanup() {
+        Log.i(TAG, "Calling nativeCleanup()");
+        nativeCleanup();
+    }
+
     private final IFusedLocationHardware mLocationHardware = new IFusedLocationHardware.Stub() {
         @Override
         public void registerSink(IFusedLocationHardwareSink eventSink) {
diff --git a/services/core/java/com/android/server/location/GpsLocationProvider.java b/services/core/java/com/android/server/location/GpsLocationProvider.java
index 5c60a61..5e5a55c 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -434,8 +434,11 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
-
             if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
+            if (action == null) {
+                return;
+            }
+
             if (action.equals(ALARM_WAKEUP)) {
                 startNavigating(false);
             } else if (action.equals(ALARM_TIMEOUT)) {
@@ -444,7 +447,8 @@
                 checkSmsSuplInit(intent);
             } else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
                 checkWapSuplInit(intent);
-            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+            } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)
+                    || action.equals(ConnectivityManager.CONNECTIVITY_ACTION_SUPL)) {
                 // retrieve NetworkType result for this UID
                 int networkType = intent.getIntExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, -1);
                 if (DEBUG) Log.d(TAG, "Connectivity action, type=" + networkType);
@@ -490,21 +494,27 @@
 
     private void checkSmsSuplInit(Intent intent) {
         SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
-
         if (messages == null) {
             Log.e(TAG, "Message does not exist in the intent.");
             return;
         }
 
-        for (int i=0; i <messages.length; i++) {
-            byte[] supl_init = messages[i].getUserData();
-            native_agps_ni_message(supl_init,supl_init.length);
+        for (SmsMessage message : messages) {
+            if (message != null && message.mWrappedSmsMessage != null) {
+                byte[] suplInit = message.getUserData();
+                if (suplInit != null) {
+                    native_agps_ni_message(suplInit, suplInit.length);
+                }
+            }
         }
     }
 
     private void checkWapSuplInit(Intent intent) {
-        byte[] supl_init = (byte[]) intent.getExtra("data");
-        native_agps_ni_message(supl_init,supl_init.length);
+        byte[] suplInit = intent.getByteArrayExtra("data");
+        if (suplInit == null) {
+            return;
+        }
+        native_agps_ni_message(suplInit,suplInit.length);
     }
 
     private void updateLowPowerMode() {
@@ -2058,6 +2068,7 @@
             intentFilter.addAction(ALARM_WAKEUP);
             intentFilter.addAction(ALARM_TIMEOUT);
             intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+            intentFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION_SUPL);
             intentFilter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
             intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
             intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index e69dda1..3991489 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -978,13 +978,12 @@
         }
 
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             final int[] idReceived = new int[1];
             mNotifManager.enqueueNotificationWithTag(
                     packageName, packageName, tag, 0x0, builder.getNotification(), idReceived,
-                    UserHandle.USER_OWNER);
+                    UserHandle.USER_ALL);
             mActiveNotifs.add(tag);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
@@ -1016,12 +1015,11 @@
                 PendingIntent.getBroadcast(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT));
 
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             final int[] idReceived = new int[1];
             mNotifManager.enqueueNotificationWithTag(packageName, packageName, tag,
-                    0x0, builder.getNotification(), idReceived, UserHandle.USER_OWNER);
+                    0x0, builder.getNotification(), idReceived, UserHandle.USER_ALL);
             mActiveNotifs.add(tag);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
@@ -1030,11 +1028,10 @@
 
     private void cancelNotification(String tag) {
         // TODO: move to NotificationManager once we can mock it
-        // XXX what to do about multi-user?
         try {
             final String packageName = mContext.getPackageName();
             mNotifManager.cancelNotificationWithTag(
-                    packageName, tag, 0x0, UserHandle.USER_OWNER);
+                    packageName, tag, 0x0, UserHandle.USER_ALL);
         } catch (RemoteException e) {
             // ignored; service lives in system_server
         }
@@ -1418,7 +1415,8 @@
                         final int policy = readIntAttribute(in, ATTR_POLICY);
 
                         // TODO: set for other users during upgrade
-                        final int uid = UserHandle.getUid(UserHandle.USER_OWNER, appId);
+                        // app policy is deprecated so this is only used in pre system user split.
+                        final int uid = UserHandle.getUid(UserHandle.USER_SYSTEM, appId);
                         if (UserHandle.isApp(uid)) {
                             setUidPolicyUncheckedLocked(uid, policy, false);
                         } else {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 0a12d5a..cbe61c3 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -46,7 +46,6 @@
 import android.service.notification.ZenModeConfig.EventInfo;
 import android.service.notification.ZenModeConfig.ScheduleInfo;
 import android.service.notification.ZenModeConfig.ZenRule;
-import android.util.ArraySet;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -149,6 +148,7 @@
             mAudioManager.setRingerModeDelegate(mRingerModeDelegate);
         }
         mHandler.postMetricsTimer();
+        evaluateZenMode("onSystemReady", true);
     }
 
     public void onUserSwitched(int user) {
@@ -330,13 +330,14 @@
         }
         mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
         mConfigs.put(config.user, config);
-        if (config.equals(mConfig)) return true;
         if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
         ZenLog.traceConfig(reason, mConfig, config);
         final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
                 getNotificationPolicy(config));
         mConfig = config;
-        dispatchOnConfigChanged();
+        if (config.equals(mConfig)) {
+            dispatchOnConfigChanged();
+        }
         if (policyChanged){
             dispatchOnPolicyChanged();
         }
@@ -370,9 +371,7 @@
 
     private boolean evaluateZenMode(String reason, boolean setRingerMode) {
         if (DEBUG) Log.d(TAG, "evaluateZenMode");
-        final ArraySet<ZenRule> automaticRules = new ArraySet<ZenRule>();
-        final int zen = computeZenMode(automaticRules);
-        if (zen == mZenMode) return false;
+        final int zen = computeZenMode();
         ZenLog.traceSetZenMode(zen, reason);
         mZenMode = zen;
         updateRingerModeAffectedStreams();
@@ -381,7 +380,9 @@
             applyZenToRingerMode();
         }
         applyRestrictions();
-        mHandler.postDispatchOnZenModeChanged();
+        if (zen != mZenMode) {
+            mHandler.postDispatchOnZenModeChanged();
+        }
         return true;
     }
 
@@ -391,7 +392,7 @@
         }
     }
 
-    private int computeZenMode(ArraySet<ZenRule> automaticRulesOut) {
+    private int computeZenMode() {
         if (mConfig == null) return Global.ZEN_MODE_OFF;
         if (mConfig.manualRule != null) return mConfig.manualRule.zenMode;
         int zen = Global.ZEN_MODE_OFF;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9e878e7..82afdd7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1146,23 +1146,24 @@
                     // need to do anything. The pending install
                     // will be processed later on.
                     if (!mBound) {
-                        try {
-                            Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindMCS",
-                                    System.identityHashCode(params));
-                            // If this is the only one pending we might
-                            // have to bind to the service again.
-                            if (!connectToService()) {
-                                Slog.e(TAG, "Failed to bind to media container service");
-                                params.serviceError();
-                                return;
-                            } else {
-                                // Once we bind to the service, the first
-                                // pending request will be processed.
-                                mPendingInstalls.add(idx, params);
+                        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
+                                System.identityHashCode(mHandler));
+                        // If this is the only one pending we might
+                        // have to bind to the service again.
+                        if (!connectToService()) {
+                            Slog.e(TAG, "Failed to bind to media container service");
+                            params.serviceError();
+                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
+                                    System.identityHashCode(mHandler));
+                            if (params.traceMethod != null) {
+                                Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, params.traceMethod,
+                                        params.traceCookie);
                             }
-                        } finally {
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindMCS",
-                                    System.identityHashCode(params));
+                            return;
+                        } else {
+                            // Once we bind to the service, the first
+                            // pending request will be processed.
+                            mPendingInstalls.add(idx, params);
                         }
                     } else {
                         mPendingInstalls.add(idx, params);
@@ -1178,6 +1179,8 @@
                     if (DEBUG_INSTALL) Slog.i(TAG, "mcs_bound");
                     if (msg.obj != null) {
                         mContainerService = (IMediaContainerService) msg.obj;
+                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "bindingMCS",
+                                System.identityHashCode(mHandler));
                     }
                     if (mContainerService == null) {
                         if (!mBound) {
@@ -1189,6 +1192,11 @@
                                 params.serviceError();
                                 Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                                         System.identityHashCode(params));
+                                if (params.traceMethod != null) {
+                                    Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER,
+                                            params.traceMethod, params.traceCookie);
+                                }
+                                return;
                             }
                             mPendingInstalls.clear();
                         } else {
@@ -1197,6 +1205,9 @@
                     } else if (mPendingInstalls.size() > 0) {
                         HandlerParams params = mPendingInstalls.get(0);
                         if (params != null) {
+                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                                    System.identityHashCode(params));
+                            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "startCopy");
                             if (params.startCopy()) {
                                 // We are done...  look for more work or to
                                 // go idle.
@@ -1225,9 +1236,8 @@
                                     mHandler.sendEmptyMessage(MCS_BOUND);
                                 }
                             }
+                            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                         }
-                        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
-                                System.identityHashCode(params));
                     } else {
                         // Should never happen ideally.
                         Slog.w(TAG, "Empty queue");
@@ -1468,6 +1478,11 @@
                                 Slog.i(TAG, "Observer no longer exists.");
                             }
                         }
+                        if (args.traceMethod != null) {
+                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, args.traceMethod,
+                                    args.traceCookie);
+                        }
+                        return;
                     } else {
                         Slog.e(TAG, "Bogus post-install token " + msg.arg1);
                     }
@@ -1551,11 +1566,12 @@
                                     state.getInstallArgs().getUser());
                         }
 
+                        Trace.asyncTraceEnd(
+                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
+
                         processPendingInstall(args, ret);
                         mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
-                    Trace.asyncTraceEnd(
-                            TRACE_TAG_PACKAGE_MANAGER, "pendingVerification", verificationId);
                     break;
                 }
                 case PACKAGE_VERIFIED: {
@@ -1591,8 +1607,10 @@
                             ret = PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE;
                         }
 
-                        processPendingInstall(args, ret);
+                        Trace.asyncTraceEnd(
+                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
 
+                        processPendingInstall(args, ret);
                         mHandler.sendEmptyMessage(MCS_UNBIND);
                     }
 
@@ -2301,16 +2319,16 @@
             }
             updatePermissionsLPw(null, null, updateFlags);
             ver.sdkVersion = mSdkVersion;
-            // clear only after permissions have been updated
-            mExistingSystemPackages.clear();
-            mPromoteSystemApps = false;
 
-            // If this is the first boot, and it is a normal boot, then
-            // we need to initialize the default preferred apps.
-            if (!mRestoredSettings && !onlyCore) {
-                mSettings.applyDefaultPreferredAppsLPw(this, UserHandle.USER_OWNER);
-                applyFactoryDefaultBrowserLPw(UserHandle.USER_OWNER);
-                primeDomainVerificationsLPw(UserHandle.USER_OWNER);
+            // If this is the first boot or an update from pre-M, and it is a normal
+            // boot, then we need to initialize the default preferred apps across
+            // all defined users.
+            if (!onlyCore && (mPromoteSystemApps || !mRestoredSettings)) {
+                for (UserInfo user : sUserManager.getUsers(true)) {
+                    mSettings.applyDefaultPreferredAppsLPw(this, user.id);
+                    applyFactoryDefaultBrowserLPw(user.id);
+                    primeDomainVerificationsLPw(user.id);
+                }
             }
 
             // If this is first boot after an OTA, and a normal boot, then
@@ -2328,6 +2346,10 @@
 
             checkDefaultBrowser();
 
+            // clear only after permissions and other defaults have been updated
+            mExistingSystemPackages.clear();
+            mPromoteSystemApps = false;
+
             // All the changes are done during package scanning.
             ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
 
@@ -4248,16 +4270,18 @@
                 if (ri != null) {
                     return ri;
                 }
+                ri = new ResolveInfo(mResolveInfo);
+                ri.activityInfo = new ActivityInfo(ri.activityInfo);
+                ri.activityInfo.applicationInfo = new ApplicationInfo(
+                        ri.activityInfo.applicationInfo);
                 if (userId != 0) {
-                    ri = new ResolveInfo(mResolveInfo);
-                    ri.activityInfo = new ActivityInfo(ri.activityInfo);
-                    ri.activityInfo.applicationInfo = new ApplicationInfo(
-                            ri.activityInfo.applicationInfo);
                     ri.activityInfo.applicationInfo.uid = UserHandle.getUid(userId,
                             UserHandle.getAppId(ri.activityInfo.applicationInfo.uid));
-                    return ri;
                 }
-                return mResolveInfo;
+                // Make sure that the resolver is displayable in car mode
+                if (ri.activityInfo.metaData == null) ri.activityInfo.metaData = new Bundle();
+                ri.activityInfo.metaData.putBoolean(Intent.METADATA_DOCK_HOME, true);
+                return ri;
             }
         }
         return null;
@@ -5975,12 +5999,6 @@
          */
         if (shouldHideSystemApp) {
             synchronized (mPackages) {
-                /*
-                 * We have to grant systems permissions before we hide, because
-                 * grantPermissions will assume the package update is trying to
-                 * expand its permissions.
-                 */
-                grantPermissionsLPw(pkg, true, pkg.packageName);
                 mSettings.disableSystemPackageLPw(pkg.packageName);
             }
         }
@@ -6262,10 +6280,26 @@
 
     @Override
     public boolean performDexOptIfNeeded(String packageName, String instructionSet) {
-        return performDexOpt(packageName, instructionSet, false);
+        return performDexOptTraced(packageName, instructionSet, false);
     }
 
-    public boolean performDexOpt(String packageName, String instructionSet, boolean backgroundDexopt) {
+    public boolean performDexOpt(
+            String packageName, String instructionSet, boolean backgroundDexopt) {
+        return performDexOptTraced(packageName, instructionSet, backgroundDexopt);
+    }
+
+    private boolean performDexOptTraced(
+            String packageName, String instructionSet, boolean backgroundDexopt) {
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+        try {
+            return performDexOptInternal(packageName, instructionSet, backgroundDexopt);
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+    }
+
+    private boolean performDexOptInternal(
+            String packageName, String instructionSet, boolean backgroundDexopt) {
         boolean dexopt = mLazyDexOpt || backgroundDexopt;
         boolean updateUsage = !backgroundDexopt;  // Don't update usage if this is just a backgroundDexopt
         if (!dexopt && !updateUsage) {
@@ -6345,8 +6379,13 @@
         synchronized (mInstallLock) {
             final String[] instructionSets = new String[] {
                     getPrimaryInstructionSet(pkg.applicationInfo) };
+
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
             final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
                     true /*forceDex*/, false /* defer */, true /* inclDependencies */);
+
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
                 throw new IllegalStateException("Failed to dexopt: " + res);
             }
@@ -7232,19 +7271,24 @@
         // We also need to dexopt any apps that are dependent on this library.  Note that
         // if these fail, we should abort the install since installing the library will
         // result in some apps being broken.
-        if (clientLibPkgs != null) {
-            if ((scanFlags & SCAN_NO_DEX) == 0) {
-                for (int i = 0; i < clientLibPkgs.size(); i++) {
-                    PackageParser.Package clientPkg = clientLibPkgs.get(i);
-                    int result = mPackageDexOptimizer.performDexOpt(clientPkg,
-                            null /* instruction sets */, forceDex,
-                            (scanFlags & SCAN_DEFER_DEX) != 0, false);
-                    if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
-                        throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
-                                "scanPackageLI failed to dexopt clientLibPkgs");
+        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+        try {
+            if (clientLibPkgs != null) {
+                if ((scanFlags & SCAN_NO_DEX) == 0) {
+                    for (int i = 0; i < clientLibPkgs.size(); i++) {
+                        PackageParser.Package clientPkg = clientLibPkgs.get(i);
+                        int result = mPackageDexOptimizer.performDexOpt(clientPkg,
+                                null /* instruction sets */, forceDex,
+                                (scanFlags & SCAN_DEFER_DEX) != 0, false);
+                        if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+                            throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
+                                    "scanPackageLI failed to dexopt clientLibPkgs");
+                        }
                     }
                 }
             }
+        } finally {
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
         // Request the ActivityManager to kill the process(only for existing packages)
@@ -7854,8 +7898,12 @@
                         ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
                         Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi);
 
+                        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
                         int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
                                 null /* instruction sets */, forceDexOpt, deferDexOpt, true);
+
+                        Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                         if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                             ps.primaryCpuAbiString = null;
                             ps.pkg.applicationInfo.primaryCpuAbi = null;
@@ -9638,16 +9686,24 @@
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(origin, null, observer, installFlags, installerPackageName,
-                null, verificationParams, user, packageAbiOverride, null);
+        final InstallParams params = new InstallParams(origin, null, observer, installFlags,
+                installerPackageName, null, verificationParams, user, packageAbiOverride, null);
+        params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
+        msg.obj = params;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installAsUser",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+
         mHandler.sendMessage(msg);
     }
 
     void installStage(String packageName, File stagedDir, String stagedCid,
-            IPackageInstallObserver2 observer, PackageInstaller.SessionParams params,
+            IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user) {
-        final VerificationParams verifParams = new VerificationParams(null, params.originatingUri,
-                params.referrerUri, installerUid, null);
+        final VerificationParams verifParams = new VerificationParams(
+                null, sessionParams.originatingUri, sessionParams.referrerUri, installerUid, null);
         verifParams.setInstallerUid(installerUid);
 
         final OriginInfo origin;
@@ -9658,10 +9714,15 @@
         }
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        msg.obj = new InstallParams(origin, null, observer, params.installFlags,
-                installerPackageName, params.volumeUuid, verifParams, user, params.abiOverride,
-                params.grantedRuntimePermissions);
+        final InstallParams params = new InstallParams(origin, null, observer,
+                sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
+                verifParams, user, sessionParams.abiOverride,
+                sessionParams.grantedRuntimePermissions);
+        params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
+        msg.obj = params;
 
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "installStage",
+                System.identityHashCode(msg.obj));
         Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
                 System.identityHashCode(msg.obj));
 
@@ -9990,6 +10051,7 @@
         if (DEBUG_INSTALL) {
             Slog.v(TAG, "BM finishing package install for " + token);
         }
+        Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
 
         final Message msg = mHandler.obtainMessage(POST_INSTALL, token, 0);
         mHandler.sendMessage(msg);
@@ -10286,8 +10348,6 @@
                         } catch (Exception e) {
                             Slog.e(TAG, "Exception trying to enqueue restore", e);
                             doRestore = false;
-                        } finally {
-                            Trace.asyncTraceEnd(TRACE_TAG_PACKAGE_MANAGER, "restore", token);
                         }
                     } else {
                         Slog.e(TAG, "Backup Manager not found!");
@@ -10320,6 +10380,8 @@
 
         /** User handle for the user requesting the information or installation. */
         private final UserHandle mUser;
+        String traceMethod;
+        int traceCookie;
 
         HandlerParams(UserHandle user) {
             mUser = user;
@@ -10329,6 +10391,16 @@
             return mUser;
         }
 
+        HandlerParams setTraceMethod(String traceMethod) {
+            this.traceMethod = traceMethod;
+            return this;
+        }
+
+        HandlerParams setTraceCookie(int traceCookie) {
+            this.traceCookie = traceCookie;
+            return this;
+        }
+
         final boolean startCopy() {
             boolean res;
             try {
@@ -10553,7 +10625,6 @@
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
 
-
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
                 VerificationParams verificationParams, UserHandle user, String packageAbiOverride,
@@ -10861,7 +10932,7 @@
                     if (ret == PackageManager.INSTALL_SUCCEEDED
                             && mRequiredVerifierPackage != null) {
                         Trace.asyncTraceBegin(
-                                TRACE_TAG_PACKAGE_MANAGER, "pendingVerification", verificationId);
+                                TRACE_TAG_PACKAGE_MANAGER, "verification", verificationId);
                         /*
                          * Send the intent to the required verification agent,
                          * but only start the verification timeout after the
@@ -10999,6 +11070,9 @@
         final UserHandle user;
         final String abiOverride;
         final String[] installGrantPermissions;
+        /** If non-null, drop an async trace when the install completes */
+        final String traceMethod;
+        final int traceCookie;
 
         // The list of instruction sets supported by this app. This is currently
         // only used during the rmdex() phase to clean up resources. We can get rid of this
@@ -11008,7 +11082,8 @@
         InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
                 ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
-                String abiOverride, String[] installGrantPermissions) {
+                String abiOverride, String[] installGrantPermissions,
+                String traceMethod, int traceCookie) {
             this.origin = origin;
             this.move = move;
             this.installFlags = installFlags;
@@ -11020,6 +11095,8 @@
             this.instructionSets = instructionSets;
             this.abiOverride = abiOverride;
             this.installGrantPermissions = installGrantPermissions;
+            this.traceMethod = traceMethod;
+            this.traceCookie = traceCookie;
         }
 
         abstract int copyApk(IMediaContainerService imcs, boolean temp) throws RemoteException;
@@ -11113,7 +11190,8 @@
             super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
-                    params.grantedRuntimePermissions);
+                    params.grantedRuntimePermissions,
+                    params.traceMethod, params.traceCookie);
             if (isFwdLocked()) {
                 throw new IllegalArgumentException("Forward locking only supported in ASEC");
             }
@@ -11122,7 +11200,7 @@
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
             super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
-                    null, null);
+                    null, null, null, 0);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
         }
@@ -11348,7 +11426,8 @@
             super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
-                    params.grantedRuntimePermissions);
+                    params.grantedRuntimePermissions,
+                    params.traceMethod, params.traceCookie);
         }
 
         /** Existing install */
@@ -11356,7 +11435,7 @@
                         boolean isExternal, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
-                    instructionSets, null, null);
+                    instructionSets, null, null, null, 0);
             // Hackily pretend we're still looking at a full code path
             if (!fullCodePath.endsWith(RES_FILE_NAME)) {
                 fullCodePath = new File(fullCodePath, RES_FILE_NAME).getAbsolutePath();
@@ -11373,7 +11452,7 @@
         AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
                     | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
-                    instructionSets, null, null);
+                    instructionSets, null, null, null, 0);
             this.cid = cid;
             setMountPath(PackageHelper.getSdDir(cid));
         }
@@ -11641,7 +11720,8 @@
             super(params.origin, params.move, params.observer, params.installFlags,
                     params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
-                    params.grantedRuntimePermissions);
+                    params.grantedRuntimePermissions,
+                    params.traceMethod, params.traceCookie);
         }
 
         int copyApk(IMediaContainerService imcs, boolean temp) {
@@ -12201,7 +12281,9 @@
             //note that the new package setting would have already been
             //added to mPackages. It hasn't been persisted yet.
             mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_INCOMPLETE);
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
             mSettings.writeLPr();
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
         if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath);
@@ -12253,7 +12335,9 @@
             mSettings.setInstallerPackageName(pkgName, installerPackageName);
             res.returnCode = PackageManager.INSTALL_SUCCEEDED;
             //to update install status
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "writeSettings");
             mSettings.writeLPr();
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -12502,9 +12586,13 @@
             }
 
             // Run dexopt before old package gets removed, to minimize time when app is unavailable
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+
             int result = mPackageDexOptimizer
                     .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
                             false /* defer */, false /* inclDependencies */);
+
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                 res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
                 return;
@@ -13728,9 +13816,14 @@
                 libDirRoot = ps.legacyNativeLibraryPathString;
             }
             if (p != null && (isExternal(p) || p.isForwardLocked())) {
-                String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
-                if (secureContainerId != null) {
-                    asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+                final long token = Binder.clearCallingIdentity();
+                try {
+                    String secureContainerId = cidFromCodePath(p.applicationInfo.getBaseCodePath());
+                    if (secureContainerId != null) {
+                        asecPath = PackageHelper.getSdFilesystem(secureContainerId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(token);
                 }
             }
         }
@@ -16194,8 +16287,16 @@
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
-        msg.obj = new InstallParams(origin, move, installObserver, installFlags,
+        final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
                 installerPackageName, volumeUuid, null, user, packageAbiOverride, null);
+        params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
+        msg.obj = params;
+
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "movePackage",
+                System.identityHashCode(msg.obj));
+        Trace.asyncTraceBegin(TRACE_TAG_PACKAGE_MANAGER, "queueInstall",
+                System.identityHashCode(msg.obj));
+
         mHandler.sendMessage(msg);
     }
 
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index c75a1d3..66170d4 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -136,9 +136,6 @@
                     case "signer":
                         policies.add(readSignerOrThrow(parser));
                         break;
-                    case "default":
-                        policies.add(readDefaultOrThrow(parser));
-                        break;
                     default:
                         skip(parser);
                 }
@@ -233,45 +230,6 @@
     }
 
     /**
-     * Loop over a default element looking for seinfo child tags. A {@link Policy}
-     * instance will be created and returned in the process. All other tags encountered
-     * will be skipped.
-     *
-     * @param parser an XmlPullParser object representing a default element.
-     * @return the constructed {@link Policy} instance
-     * @throws IOException
-     * @throws XmlPullParserException
-     * @throws IllegalArgumentException if any of the validation checks fail while
-     *         parsing tag values.
-     * @throws IllegalStateException if any of the invariants fail when constructing
-     *         the {@link Policy} instance.
-     */
-    private static Policy readDefaultOrThrow(XmlPullParser parser) throws IOException,
-            XmlPullParserException {
-
-        parser.require(XmlPullParser.START_TAG, null, "default");
-        Policy.PolicyBuilder pb = new Policy.PolicyBuilder();
-        pb.setAsDefaultPolicy();
-
-        while (parser.next() != XmlPullParser.END_TAG) {
-            if (parser.getEventType() != XmlPullParser.START_TAG) {
-                continue;
-            }
-
-            String tagName = parser.getName();
-            if ("seinfo".equals(tagName)) {
-                String seinfo = parser.getAttributeValue(null, "value");
-                pb.setGlobalSeinfoOrThrow(seinfo);
-                readSeinfo(parser);
-            } else {
-                skip(parser);
-            }
-        }
-
-        return pb.build();
-    }
-
-    /**
      * Loop over a package element looking for seinfo child tags. If found return the
      * value attribute of the seinfo tag, otherwise return null. All other tags encountered
      * will be skipped.
@@ -337,35 +295,28 @@
 
     /**
      * Applies a security label to a package based on an seinfo tag taken from a matched
-     * policy. All signature based policy stanzas are consulted first and, if no match
-     * is found, the default policy stanza is then consulted. The security label is
-     * attached to the ApplicationInfo instance of the package in the event that a matching
-     * policy was found.
+     * policy. All signature based policy stanzas are consulted and, if no match is
+     * found, the default seinfo label of 'default' (set in ApplicationInfo object) is
+     * used. The security label is attached to the ApplicationInfo instance of the package
+     * in the event that a matching policy was found.
      *
      * @param pkg object representing the package to be labeled.
-     * @return boolean which determines whether a non null seinfo label was assigned
-     *         to the package. A null value simply represents that no policy matched.
      */
-    public static boolean assignSeinfoValue(PackageParser.Package pkg) {
+    public static void assignSeinfoValue(PackageParser.Package pkg) {
         synchronized (sPolicies) {
             for (Policy policy : sPolicies) {
                 String seinfo = policy.getMatchedSeinfo(pkg);
                 if (seinfo != null) {
                     pkg.applicationInfo.seinfo = seinfo;
-                    if (DEBUG_POLICY_INSTALL) {
-                        Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
-                               "seinfo=" + seinfo);
-                    }
-                    return true;
+                    break;
                 }
             }
         }
 
         if (DEBUG_POLICY_INSTALL) {
-            Slog.i(TAG, "package (" + pkg.packageName + ") doesn't match any policy; " +
-                   "seinfo will remain null");
+            Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
+                    "seinfo=" + pkg.applicationInfo.seinfo);
         }
-        return false;
     }
 
     /**
@@ -506,30 +457,16 @@
  *         .build();
  * }
  * </pre>
- * <p>
- * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
- * default based Policy instance.
- * </p>
- * <pre>
- * {@code
- * Policy policy = new Policy.PolicyBuilder()
- *         .setAsDefaultPolicy()
- *         .setGlobalSeinfoOrThrow("default")
- *         .build();
- * }
- * </pre>
  */
 final class Policy {
 
     private final String mSeinfo;
-    private final boolean mDefaultStanza;
     private final Set<Signature> mCerts;
     private final Map<String, String> mPkgMap;
 
     // Use the PolicyBuilder pattern to instantiate
     private Policy(PolicyBuilder builder) {
         mSeinfo = builder.mSeinfo;
-        mDefaultStanza = builder.mDefaultStanza;
         mCerts = Collections.unmodifiableSet(builder.mCerts);
         mPkgMap = Collections.unmodifiableMap(builder.mPkgMap);
     }
@@ -545,15 +482,6 @@
     }
 
     /**
-     * Return whether this policy object represents a default stanza.
-     *
-     * @return A boolean indicating if this object represents a default policy stanza.
-     */
-    public boolean isDefaultStanza() {
-        return mDefaultStanza;
-    }
-
-    /**
      * Return whether this policy object contains package name mapping refinements.
      *
      * @return A boolean indicating if this object has inner package name mappings.
@@ -584,10 +512,6 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        if (mDefaultStanza) {
-            sb.append("defaultStanza=true ");
-        }
-
         for (Signature cert : mCerts) {
             sb.append("cert=" + cert.toCharsString().substring(0, 11) + "... ");
         }
@@ -609,22 +533,15 @@
      * is determined using the following steps:
      * </p>
      * <ul>
-     *   <li> If this Policy instance is defined as a default stanza:
-     *       <ul><li>Return the global seinfo value</li></ul>
+     *   <li> All certs used to sign the apk and all certs stored with this policy
+     *     instance are tested for set equality. If this fails then null is returned.
      *   </li>
-     *   <li> If this Policy instance is defined as a signer stanza:
-     *     <ul>
-     *       <li> All certs used to sign the apk and all certs stored with this policy
-     *         instance are tested for set equality. If this fails then null is returned.
-     *       </li>
-     *       <li> If all certs match then an appropriate inner package stanza is
-     *         searched based on package name alone. If matched, the stored seinfo
-     *         value for that mapping is returned.
-     *       </li>
-     *       <li> If all certs matched and no inner package stanza matches then return
-     *         the global seinfo value. The returned value can be null in this case.
-     *       </li>
-     *     </ul>
+     *   <li> If all certs match then an appropriate inner package stanza is
+     *     searched based on package name alone. If matched, the stored seinfo
+     *     value for that mapping is returned.
+     *   </li>
+     *   <li> If all certs matched and no inner package stanza matches then return
+     *     the global seinfo value. The returned value can be null in this case.
      *   </li>
      * </ul>
      * <p>
@@ -636,37 +553,34 @@
      *         A value of null can also be returned if no match occured.
      */
     public String getMatchedSeinfo(PackageParser.Package pkg) {
-        if (!mDefaultStanza) {
-            // Check for exact signature matches across all certs.
-            Signature[] certs = mCerts.toArray(new Signature[0]);
-            if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
-                return null;
-            }
-
-            // Check for inner package name matches given that the
-            // signature checks already passed.
-            String seinfoValue = mPkgMap.get(pkg.packageName);
-            if (seinfoValue != null) {
-                return seinfoValue;
-            }
+        // Check for exact signature matches across all certs.
+        Signature[] certs = mCerts.toArray(new Signature[0]);
+        if (!Signature.areExactMatch(certs, pkg.mSignatures)) {
+            return null;
         }
 
-        // Return the global seinfo value (even if it's null).
+        // Check for inner package name matches given that the
+        // signature checks already passed.
+        String seinfoValue = mPkgMap.get(pkg.packageName);
+        if (seinfoValue != null) {
+            return seinfoValue;
+        }
+
+        // Return the global seinfo value.
         return mSeinfo;
     }
 
     /**
      * A nested builder class to create {@link Policy} instances. A {@link Policy}
      * class instance represents one valid policy stanza found in a mac_permissions.xml
-     * file. A valid policy stanza is defined to be either a signer or default stanza
-     * which obeys the rules outlined in external/sepolicy/mac_permissions.xml. The
-     * {@link #build} method ensures a set of invariants are upheld enforcing the correct
-     * stanza structure before returning a valid Policy object.
+     * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
+     * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+     * ensures a set of invariants are upheld enforcing the correct stanza structure
+     * before returning a valid Policy object.
      */
     public static final class PolicyBuilder {
 
         private String mSeinfo;
-        private boolean mDefaultStanza;
         private final Set<Signature> mCerts;
         private final Map<String, String> mPkgMap;
 
@@ -676,19 +590,6 @@
         }
 
         /**
-         * Sets this stanza as a default stanza. All policy stanzas are assumed to
-         * be signer stanzas unless this method is explicitly called. Default stanzas
-         * are treated differently with respect to allowable child tags, ordering and
-         * when and how policy decisions are enforced.
-         *
-         * @return The reference to this PolicyBuilder.
-         */
-        public PolicyBuilder setAsDefaultPolicy() {
-            mDefaultStanza = true;
-            return this;
-        }
-
-        /**
          * Adds a signature to the set of certs used for validation checks. The purpose
          * being that all contained certs will need to be matched against all certs
          * contained with an apk.
@@ -710,11 +611,8 @@
 
         /**
          * Set the global seinfo tag for this policy stanza. The global seinfo tag
-         * represents the seinfo element that is used in one of two ways depending on
-         * its context. When attached to a signer tag the global seinfo represents an
-         * assignment when there isn't a further inner package refinement in policy.
-         * When used with a default tag, it represents the only allowable assignment
-         * value.
+         * when attached to a signer tag represents the assignment when there isn't a
+         * further inner package refinement in policy.
          *
          * @param seinfo the seinfo value given as a String.
          * @return The reference to this PolicyBuilder.
@@ -740,9 +638,7 @@
         /**
          * Create a package name to seinfo value mapping. Each mapping represents
          * the seinfo value that will be assigned to the described package name.
-         * These localized mappings allow the global seinfo to be overriden. This
-         * mapping provides no value when used in conjunction with a default stanza;
-         * enforced through the {@link #build} method.
+         * These localized mappings allow the global seinfo to be overriden.
          *
          * @param pkgName the android package name given to the app
          * @param seinfo the seinfo value that will be assigned to the passed pkgName
@@ -799,51 +695,25 @@
          * about the expected structure of a policy stanza.
          * Those invariants are:
          * </p>
-         *    <ul>
-         *      <li> If a default stanza
-         *        <ul>
-         *          <li> an attached global seinfo tag must be present </li>
-         *          <li> no signatures and no package names can be present </li>
-         *        </ul>
-         *      </li>
-         *      <li> If a signer stanza
-         *        <ul>
-         *           <li> at least one cert must be found </li>
-         *           <li> either a global seinfo value is present OR at least one
-         *           inner package mapping must be present BUT not both. </li>
-         *        </ul>
-         *      </li>
-         *    </ul>
-         *
+         * <ul>
+         *   <li> at least one cert must be found </li>
+         *   <li> either a global seinfo value is present OR at least one
+         *     inner package mapping must be present BUT not both. </li>
+         * </ul>
          * @return an instance of {@link Policy} with the options set from this builder
          * @throws IllegalStateException if an invariant is violated.
          */
         public Policy build() {
             Policy p = new Policy(this);
 
-            if (p.mDefaultStanza) {
-                if (p.mSeinfo == null) {
-                    String err = "Missing global seinfo tag with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-                if (p.mCerts.size() != 0) {
-                    String err = "Certs not allowed with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-                if (!p.mPkgMap.isEmpty()) {
-                    String err = "Inner package mappings not allowed with default stanza.";
-                    throw new IllegalStateException(err);
-                }
-            } else {
-                if (p.mCerts.size() == 0) {
-                    String err = "Missing certs with signer tag. Expecting at least one.";
-                    throw new IllegalStateException(err);
-                }
-                if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
-                    String err = "Only seinfo tag XOR package tags are allowed within " +
-                            "a signer stanza.";
-                    throw new IllegalStateException(err);
-                }
+            if (p.mCerts.isEmpty()) {
+                String err = "Missing certs with signer tag. Expecting at least one.";
+                throw new IllegalStateException(err);
+            }
+            if (!(p.mSeinfo == null ^ p.mPkgMap.isEmpty())) {
+                String err = "Only seinfo tag XOR package tags are allowed within " +
+                        "a signer stanza.";
+                throw new IllegalStateException(err);
             }
 
             return p;
@@ -858,7 +728,6 @@
  * <ul>
  *   <li> signer stanzas with inner package mappings </li>
  *   <li> signer stanzas with global seinfo tags </li>
- *   <li> default stanza </li>
  * </ul>
  * This comparison also checks for duplicate entries on the input selectors. Any
  * found duplicates will be flagged and can be checked with {@link #foundDuplicate}.
@@ -875,11 +744,6 @@
     @Override
     public int compare(Policy p1, Policy p2) {
 
-        // Give precedence to signature stanzas over default stanzas
-        if (p1.isDefaultStanza() != p2.isDefaultStanza()) {
-            return p1.isDefaultStanza() ? 1 : -1;
-        }
-
         // Give precedence to stanzas with inner package mappings
         if (p1.hasInnerPackages() != p2.hasInnerPackages()) {
             return p1.hasInnerPackages() ? -1 : 1;
@@ -887,7 +751,7 @@
 
         // Check for duplicate entries
         if (p1.getSignatures().equals(p2.getSignatures())) {
-            // Checks if default stanza or a signer w/o inner package names
+            // Checks if signer w/o inner package names
             if (p1.hasGlobalSeinfo()) {
                 duplicateFound = true;
                 Slog.e(SELinuxMMAC.TAG, "Duplicate policy entry: " + p1.toString());
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 4bfcb90..1924bab 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -61,7 +61,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
-import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
 
@@ -102,6 +101,7 @@
     private static final String ATTR_GUEST_TO_REMOVE = "guestToRemove";
     private static final String ATTR_USER_VERSION = "version";
     private static final String ATTR_PROFILE_GROUP_ID = "profileGroupId";
+    private static final String ATTR_RESTRICTED_PROFILE_PARENT_ID = "restrictedProfileParentId";
     private static final String TAG_GUEST_RESTRICTIONS = "guestRestrictions";
     private static final String TAG_USERS = "users";
     private static final String TAG_USER = "user";
@@ -927,7 +927,10 @@
                 serializer.attribute(null, ATTR_PROFILE_GROUP_ID,
                         Integer.toString(userInfo.profileGroupId));
             }
-
+            if (userInfo.restrictedProfileParentId != UserInfo.NO_PROFILE_GROUP_ID) {
+                serializer.attribute(null, ATTR_RESTRICTED_PROFILE_PARENT_ID,
+                        Integer.toString(userInfo.restrictedProfileParentId));
+            }
             serializer.startTag(null, TAG_NAME);
             serializer.text(userInfo.name);
             serializer.endTag(null, TAG_NAME);
@@ -1037,6 +1040,7 @@
         long creationTime = 0L;
         long lastLoggedInTime = 0L;
         int profileGroupId = UserInfo.NO_PROFILE_GROUP_ID;
+        int restrictedProfileParentId = UserInfo.NO_PROFILE_GROUP_ID;
         boolean partial = false;
         boolean guestToRemove = false;
         Bundle restrictions = new Bundle();
@@ -1072,6 +1076,8 @@
                 lastLoggedInTime = readLongAttribute(parser, ATTR_LAST_LOGGED_IN_TIME, 0);
                 profileGroupId = readIntAttribute(parser, ATTR_PROFILE_GROUP_ID,
                         UserInfo.NO_PROFILE_GROUP_ID);
+                restrictedProfileParentId = readIntAttribute(parser,
+                        ATTR_RESTRICTED_PROFILE_PARENT_ID, UserInfo.NO_PROFILE_GROUP_ID);
                 String valueString = parser.getAttributeValue(null, ATTR_PARTIAL);
                 if ("true".equals(valueString)) {
                     partial = true;
@@ -1106,6 +1112,7 @@
             userInfo.partial = partial;
             userInfo.guestToRemove = guestToRemove;
             userInfo.profileGroupId = profileGroupId;
+            userInfo.restrictedProfileParentId = restrictedProfileParentId;
             mUserRestrictions.append(id, restrictions);
             return userInfo;
 
@@ -1262,6 +1269,7 @@
         }
         final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
         final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
+        final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
         final long ident = Binder.clearCallingIdentity();
         UserInfo userInfo = null;
         final int userId;
@@ -1286,6 +1294,24 @@
                     if (isGuest && findCurrentGuestUserLocked() != null) {
                         return null;
                     }
+                    // In legacy mode, restricted profile's parent can only be the owner user
+                    if (isRestricted && !UserManager.isSplitSystemUser()
+                            && (parentId != UserHandle.USER_SYSTEM)) {
+                        Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
+                        return null;
+                    }
+                    if (isRestricted && UserManager.isSplitSystemUser()) {
+                        if (parent == null) {
+                            Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be "
+                                    + "specified");
+                            return null;
+                        }
+                        if (!parent.canHaveProfile()) {
+                            Log.w(LOG_TAG, "Cannot add restricted profile - profiles cannot be "
+                                    + "created for the specified parent user id " + parentId);
+                            return null;
+                        }
+                    }
                     // In split system user mode, we assign the first human user the primary flag.
                     // And if there is no device owner, we also assign the admin flag to primary
                     // user.
@@ -1309,11 +1335,22 @@
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
                     if (parent != null) {
-                        if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
-                            parent.profileGroupId = parent.id;
-                            scheduleWriteUserLocked(parent);
+                        if (isManagedProfile) {
+                            if (parent.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID) {
+                                parent.profileGroupId = parent.id;
+                                scheduleWriteUserLocked(parent);
+                            }
+                            userInfo.profileGroupId = parent.profileGroupId;
+                        } else if (isRestricted) {
+                            if (!parent.canHaveProfile()) {
+                                Log.w(LOG_TAG, "Cannot add restricted profile - parent user must be owner");
+                            }
+                            if (parent.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID) {
+                                parent.restrictedProfileParentId = parent.id;
+                                scheduleWriteUserLocked(parent);
+                            }
+                            userInfo.restrictedProfileParentId = parent.restrictedProfileParentId;
                         }
-                        userInfo.profileGroupId = parent.profileGroupId;
                     }
                     final StorageManager storage = mContext.getSystemService(StorageManager.class);
                     for (VolumeInfo vol : storage.getWritablePrivateVolumes()) {
@@ -1348,24 +1385,9 @@
         return userInfo;
     }
 
-    private int numberOfUsersOfTypeLocked(int flags, boolean excludeDying) {
-        int count = 0;
-        for (int i = mUsers.size() - 1; i >= 0; i--) {
-            UserInfo user = mUsers.valueAt(i);
-            if (!excludeDying || !mRemovingUserIds.get(user.id)) {
-                if ((user.flags & flags) != 0) {
-                    count++;
-                }
-            }
-        }
-        return count;
-    }
-
     /**
      * Find the current guest user. If the Guest user is partial,
      * then do not include it in the results as it is about to die.
-     * This is different than {@link #numberOfUsersOfTypeLocked(int, boolean)} due to
-     * the special handling of Guests being removed.
      */
     private UserInfo findCurrentGuestUserLocked() {
         final int size = mUsers.size();
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4aaba14..4d67702 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -65,6 +65,7 @@
 import android.os.Message;
 import android.os.Messenger;
 import android.os.PowerManager;
+import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -265,6 +266,7 @@
     WindowManagerFuncs mWindowManagerFuncs;
     WindowManagerInternal mWindowManagerInternal;
     PowerManager mPowerManager;
+    PowerManagerInternal mPowerManagerInternal;
     ActivityManagerInternal mActivityManagerInternal;
     DreamManagerInternal mDreamManagerInternal;
     IStatusBarService mStatusBarService;
@@ -773,6 +775,13 @@
     }
 
     class MyOrientationListener extends WindowOrientationListener {
+        private final Runnable mUpdateRotationRunnable = new Runnable() {
+            @Override
+            public void run() {
+                updateRotation(false);
+            }
+        };
+
         MyOrientationListener(Context context, Handler handler) {
             super(context, handler);
         }
@@ -780,7 +789,7 @@
         @Override
         public void onProposedRotationChanged(int rotation) {
             if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
-            updateRotation(false);
+            mHandler.post(mUpdateRotationRunnable);
         }
     }
     MyOrientationListener mOrientationListener;
@@ -1328,6 +1337,7 @@
         mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
 
         // Init display burn-in protection
         boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -4455,7 +4465,7 @@
                     if (mAppsToBeHidden.isEmpty()) {
                         if (dismissKeyguard && !mKeyguardSecure) {
                             mAppsThatDismissKeyguard.add(appToken);
-                        } else if (win.isDrawnLw()) {
+                        } else if (win.isDrawnLw() || win.hasAppShownWindows()) {
                             mWinShowWhenLocked = win;
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
@@ -4489,7 +4499,8 @@
                         mWinDismissingKeyguard = win;
                         mSecureDismissingKeyguard = mKeyguardSecure;
                         mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
-                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
+                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked
+                            && (win.isDrawnLw() || win.hasAppShownWindows())) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
                                 "Setting mHideLockScreen to true by win " + win);
                         mHideLockScreen = true;
@@ -5117,6 +5128,15 @@
                 break;
             }
 
+            case KeyEvent.KEYCODE_SOFT_SLEEP: {
+                result &= ~ACTION_PASS_TO_USER;
+                isWakeKey = false;
+                if (!down) {
+                    mPowerManagerInternal.setUserInactiveOverrideFromWindowManager();
+                }
+                break;
+            }
+
             case KeyEvent.KEYCODE_WAKEUP: {
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = true;
@@ -6625,6 +6645,11 @@
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
+
+        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
+            tmpVisibility |= StatusBarManager.DISABLE_RECENT;
+        }
+
         tmpVisibility = updateLightStatusBarLw(tmpVisibility);
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 7ebb7f8..4e702aa 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -393,6 +393,10 @@
     // Use -1 to disable.
     private int mScreenBrightnessOverrideFromWindowManager = -1;
 
+    // The window manager has determined the user to be inactive via other means.
+    // Set this to false to disable.
+    private boolean mUserInactiveOverrideFromWindowManager;
+
     // The user activity timeout override from the window manager
     // to allow the current foreground activity to override the user activity timeout.
     // Use -1 to disable.
@@ -1028,6 +1032,10 @@
 
             mNotifier.onUserActivity(event, uid);
 
+            if (mUserInactiveOverrideFromWindowManager) {
+                mUserInactiveOverrideFromWindowManager = false;
+            }
+
             if (mWakefulness == WAKEFULNESS_ASLEEP
                     || mWakefulness == WAKEFULNESS_DOZING
                     || (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
@@ -1525,6 +1533,7 @@
                 final int sleepTimeout = getSleepTimeoutLocked();
                 final int screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout);
                 final int screenDimDuration = getScreenDimDurationLocked(screenOffTimeout);
+                final boolean userInactiveOverride = mUserInactiveOverrideFromWindowManager;
 
                 mUserActivitySummary = 0;
                 if (mLastUserActivityTime >= mLastWakeTime) {
@@ -1550,6 +1559,7 @@
                         }
                     }
                 }
+
                 if (mUserActivitySummary == 0) {
                     if (sleepTimeout >= 0) {
                         final long anyUserActivity = Math.max(mLastUserActivityTime,
@@ -1565,6 +1575,12 @@
                         nextTimeout = -1;
                     }
                 }
+
+                if (mUserActivitySummary != USER_ACTIVITY_SCREEN_DREAM && userInactiveOverride) {
+                    mUserActivitySummary = USER_ACTIVITY_SCREEN_DREAM;
+                    nextTimeout = -1;
+                }
+
                 if (mUserActivitySummary != 0 && nextTimeout >= 0) {
                     Message msg = mHandler.obtainMessage(MSG_USER_ACTIVITY_TIMEOUT);
                     msg.setAsynchronous(true);
@@ -2494,6 +2510,14 @@
         }
     }
 
+    private void setUserInactiveOverrideFromWindowManagerInternal() {
+        synchronized (mLock) {
+            mUserInactiveOverrideFromWindowManager = true;
+            mDirty |= DIRTY_USER_ACTIVITY;
+            updatePowerStateLocked();
+        }
+    }
+
     private void setUserActivityTimeoutOverrideFromWindowManagerInternal(long timeoutMillis) {
         synchronized (mLock) {
             if (mUserActivityTimeoutOverrideFromWindowManager != timeoutMillis) {
@@ -2688,6 +2712,8 @@
                     + mScreenBrightnessOverrideFromWindowManager);
             pw.println("  mUserActivityTimeoutOverrideFromWindowManager="
                     + mUserActivityTimeoutOverrideFromWindowManager);
+            pw.println("  mUserInactiveOverrideFromWindowManager="
+                    + mUserInactiveOverrideFromWindowManager);
             pw.println("  mTemporaryScreenBrightnessSettingOverride="
                     + mTemporaryScreenBrightnessSettingOverride);
             pw.println("  mTemporaryScreenAutoBrightnessAdjustmentSettingOverride="
@@ -3492,6 +3518,11 @@
         }
 
         @Override
+        public void setUserInactiveOverrideFromWindowManager() {
+            setUserInactiveOverrideFromWindowManagerInternal();
+        }
+
+        @Override
         public void setUserActivityTimeoutOverrideFromWindowManager(long timeoutMillis) {
             setUserActivityTimeoutOverrideFromWindowManagerInternal(timeoutMillis);
         }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index a210223..6ee2c39 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -112,6 +112,11 @@
     boolean mLaunchTaskBehind;
     boolean mEnteringAnimation;
 
+    // This application will have its window replaced due to relaunch. This allows window manager
+    // to differentiate between simple removal of a window and replacement. In the latter case it
+    // will preserve the old window until the new one is drawn.
+    boolean mReplacingWindow;
+
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
         super(_service, _token.asBinder(),
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 554af28..666d902 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -23,7 +23,6 @@
 
 import android.content.res.Configuration;
 import android.graphics.Rect;
-import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -41,13 +40,6 @@
      * when no window animation is driving it. */
     private static final int DEFAULT_DIM_DURATION = 200;
 
-    // The amount we divide the height/width of the bounds we are trying to fit the task within
-    // when using the method {@link #fitWithinBounds}.
-    // We always want the task to to be visible in the bounds without affecting its size when
-    // fitting. To make sure this is the case, we don't adjust the task left or top side pass
-    // the input bounds right or bottom side minus the width or height divided by this value.
-    private static final int FIT_WITHIN_BOUNDS_DIVIDER = 3;
-
     TaskStack mStack;
     final AppTokenList mAppTokens = new AppTokenList();
     final int mTaskId;
@@ -84,13 +76,13 @@
     // of creating a new object per fullscreen task on a display.
     private static final SparseArray<DimLayer> sSharedFullscreenDimLayers = new SparseArray<>();
 
-    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds) {
+    Task(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+            Configuration config) {
         mTaskId = taskId;
         mStack = stack;
         mUserId = userId;
         mService = service;
-        mOverrideConfig = Configuration.EMPTY;
-        setBounds(bounds);
+        setBounds(bounds, config);
     }
 
     DisplayContent getDisplayContent() {
@@ -172,43 +164,18 @@
         }
     }
 
-    /** Fits the tasks within the input bounds adjusting the task bounds as needed.
-     *  @param bounds Bounds to fit the task within. Nothing is done if null.
-     *  @return Returns true if the task bounds was adjusted in any way.
-     *  */
-    boolean fitWithinBounds(Rect bounds) {
-        if (bounds == null || bounds.contains(mBounds)) {
-            return false;
-        }
-        mTmpRect2.set(mBounds);
-
-        if (mBounds.left < bounds.left || mBounds.right > bounds.right) {
-            final int maxRight = bounds.right - (bounds.width() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int horizontalDiff = bounds.left - mBounds.left;
-            if ((horizontalDiff < 0 && mBounds.left >= maxRight)
-                    || (mBounds.left + horizontalDiff >= maxRight)) {
-                horizontalDiff = maxRight - mBounds.left;
-            }
-            mTmpRect2.left += horizontalDiff;
-            mTmpRect2.right += horizontalDiff;
-        }
-
-        if (mBounds.top < bounds.top || mBounds.bottom > bounds.bottom) {
-            final int maxBottom = bounds.bottom - (bounds.height() / FIT_WITHIN_BOUNDS_DIVIDER);
-            int verticalDiff = bounds.top - mBounds.top;
-            if ((verticalDiff < 0 && mBounds.top >= maxBottom)
-                    || (mBounds.top + verticalDiff >= maxBottom)) {
-                verticalDiff = maxBottom - mBounds.top;
-            }
-            mTmpRect2.top += verticalDiff;
-            mTmpRect2.bottom += verticalDiff;
-        }
-
-        return setBounds(mTmpRect2);
-    }
-
     /** Set the task bounds. Passing in null sets the bounds to fullscreen. */
-    boolean setBounds(Rect bounds) {
+    boolean setBounds(Rect bounds, Configuration config) {
+        if (config == null) {
+            config = Configuration.EMPTY;
+        }
+        if (bounds == null && !Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("null bounds but non empty configuration: "
+                    + config);
+        }
+        if (bounds != null && Configuration.EMPTY.equals(config)) {
+            throw new IllegalArgumentException("non null bounds, but empty configuration");
+        }
         boolean oldFullscreen = mFullscreen;
         int rotation = Surface.ROTATION_0;
         final DisplayContent displayContent = mStack.getDisplayContent();
@@ -241,7 +208,7 @@
         mBounds.set(bounds);
         mRotation = rotation;
         updateDimLayer();
-        updateOverrideConfiguration();
+        mOverrideConfig = mFullscreen ? Configuration.EMPTY : config;
         return true;
     }
 
@@ -249,36 +216,12 @@
         out.set(mBounds);
     }
 
-    private void updateOverrideConfiguration() {
-        final Configuration serviceConfig = mService.mCurConfiguration;
-        if (mFullscreen) {
-            mOverrideConfig = Configuration.EMPTY;
-            return;
-        }
-
-        if (mOverrideConfig == Configuration.EMPTY) {
-            mOverrideConfig  = new Configuration();
-        }
-
-        // TODO(multidisplay): Update Dp to that of display stack is on.
-        final float density = serviceConfig.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-        mOverrideConfig.screenWidthDp =
-                Math.min((int)(mBounds.width() / density), serviceConfig.screenWidthDp);
-        mOverrideConfig.screenHeightDp =
-                Math.min((int)(mBounds.height() / density), serviceConfig.screenHeightDp);
-        mOverrideConfig.smallestScreenWidthDp =
-                Math.min(mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp);
-        mOverrideConfig.orientation =
-                (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp)
-                        ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE;
-    }
-
     void updateDisplayInfo(final DisplayContent displayContent) {
         if (displayContent == null) {
             return;
         }
         if (mFullscreen) {
-            setBounds(null);
+            setBounds(null, Configuration.EMPTY);
             return;
         }
         final int newRotation = displayContent.getDisplayInfo().rotation;
@@ -313,7 +256,7 @@
                 mTmpRect2.bottom = mTmpRect2.top + mBounds.width();
                 break;
         }
-        setBounds(mTmpRect2);
+        setBounds(mTmpRect2, mOverrideConfig);
     }
 
     /** Updates the dim layer bounds, recreating it if needed. */
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 25a71d9..f21f00a 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -27,6 +27,7 @@
 import android.util.EventLog;
 import android.util.IntArray;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.view.DisplayInfo;
 
 import com.android.server.EventLogTags;
@@ -96,15 +97,15 @@
 
     /**
      * Set the bounds of the stack and its containing tasks.
-     * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
+     * @param stackBounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configuration for individual tasks, keyed by task id.
+     * @param taskBounds Bounds for individual tasks, keyed by task id.
      * @return True if the stack bounds was changed.
      * */
-    boolean setBounds(Rect bounds, boolean resizeTasks, IntArray changedTaskIds,
-            List<Configuration> newTaskConfigs) {
-        if (!setBounds(bounds)) {
+    boolean setBounds(Rect stackBounds, boolean resizeTasks, SparseArray<Configuration> configs,
+            SparseArray<Rect> taskBounds) {
+        if (!setBounds(stackBounds)) {
             return false;
         }
 
@@ -113,20 +114,17 @@
         }
 
         // Update bounds of containing tasks.
-        final Rect newBounds = mFullscreen ? null : mBounds;
         for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
             final Task task = mTasks.get(taskNdx);
-            if (mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                // For freeform stack we don't adjust the size of the tasks to match that of the
-                // stack, but we do try to make sure the tasks are still contained with the
-                // bounds of the stack.
-                if (task.fitWithinBounds(newBounds)) {
-                    changedTaskIds.add(task.mTaskId);
-                    newTaskConfigs.add(task.mOverrideConfig);
+            Configuration config = configs.get(task.mTaskId);
+            if (config != null) {
+                Rect bounds = taskBounds.get(task.mTaskId);
+                if (bounds == null) {
+                    bounds = stackBounds;
                 }
-            } else if (task.setBounds(newBounds)) {
-                changedTaskIds.add(task.mTaskId);
-                newTaskConfigs.add(task.mOverrideConfig);
+                task.setBounds(bounds, config);
+            } else {
+                Slog.wtf(TAG, "No config for task: " + task + ", is there a mismatch with AM?");
             }
         }
         return true;
@@ -407,7 +405,10 @@
             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(appWindows.get(winNdx));
+                    // We are in the middle of changing the state of displays/stacks/tasks. We need
+                    // to finish that, before we let layout interfere with it.
+                    mService.removeWindowInnerLocked(appWindows.get(winNdx),
+                            false /* performLayout */);
                     doAnotherLayoutPass = true;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index d0962f4..fc23fd1 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -750,7 +750,7 @@
     }
 
     boolean adjustWallpaperWindows() {
-        mService.mInnerFields.mWallpaperMayChange = false;
+        mService.mWindowPlacerLocked.mWallpaperMayChange = false;
 
         final WindowList windows = mService.getDefaultWindowListLocked();
         // First find top-most window that has asked to be on top of the wallpaper;
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index e6a1be1..b334a05 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -23,11 +23,11 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerService.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_UPDATE_ROTATION;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_MAY_CHANGE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_FORCE_HIDING_CHANGED;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_WALLPAPER_ACTION_PENDING;
+import static com.android.server.wm.WindowSurfacePlacer.SET_UPDATE_ROTATION;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_WALLPAPER_ACTION_PENDING;
 
 import android.content.Context;
 import android.os.RemoteException;
@@ -41,8 +41,6 @@
 import android.view.animation.Animation;
 import android.view.Choreographer;
 
-import com.android.server.wm.WindowManagerService.LayoutFields;
-
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
@@ -84,8 +82,7 @@
     int mBulkUpdateParams = 0;
     Object mLastWindowFreezeSource;
 
-    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators =
-            new SparseArray<DisplayContentsAnimator>(2);
+    SparseArray<DisplayContentsAnimator> mDisplayContentsAnimators = new SparseArray<>(2);
 
     boolean mInitialized = false;
 
@@ -179,10 +176,12 @@
                     mAnimating = mAppWindowAnimating = true;
                 } else if (appAnimator.wasAnimating) {
                     // stopped animating, do one more pass through the layout
-                    setAppLayoutChanges(appAnimator, WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
-                        "exiting appToken " + appAnimator.mAppToken + " done", displayId);
+                    setAppLayoutChanges(appAnimator,
+                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
+                            "exiting appToken " + appAnimator.mAppToken + " done", displayId);
                     if (WindowManagerService.DEBUG_ANIM) Slog.v(TAG,
-                            "updateWindowsApps...: done animating exiting " + appAnimator.mAppToken);
+                            "updateWindowsApps...: done animating exiting "
+                                    + appAnimator.mAppToken);
                 }
             }
         }
@@ -301,7 +300,8 @@
                     setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                     if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                        mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2",
+                        mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                "updateWindowsAndWallpaperLocked 2",
                                 getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                     }
                 }
@@ -315,7 +315,8 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 3",
                                     getPendingLayoutChanges(displayId));
                         }
                         mService.mFocusMayChange = true;
@@ -409,7 +410,8 @@
                         setPendingLayoutChanges(Display.DEFAULT_DISPLAY,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 4",
                                     getPendingLayoutChanges(Display.DEFAULT_DISPLAY));
                         }
                     }
@@ -433,7 +435,8 @@
                         setPendingLayoutChanges(displayId,
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                         if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                            mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5",
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "updateWindowsAndWallpaperLocked 5",
                                     getPendingLayoutChanges(displayId));
                         }
                     }
@@ -607,7 +610,8 @@
                                     "Setting mOrientationChangeComplete=true because wtoken "
                                     + wtoken + " numInteresting=" + wtoken.numInterestingWindows
                                     + " numDrawn=" + wtoken.numDrawnWindows);
-                            // This will set mOrientationChangeComplete and cause a pass through layout.
+                            // This will set mOrientationChangeComplete and cause a pass through
+                            // layout.
                             setAppLayoutChanges(appAnimator,
                                     WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER,
                                     "testTokenMayBeDrawnLocked: freezingScreen", displayId);
@@ -737,7 +741,7 @@
 
         boolean doRequest = false;
         if (mBulkUpdateParams != 0) {
-            doRequest = mService.copyAnimToLayoutParamsLocked();
+            doRequest = mService.mWindowPlacerLocked.copyAnimToLayoutParamsLocked();
         }
 
         if (hasPendingLayoutChanges || doRequest) {
@@ -755,21 +759,21 @@
         }
     }
 
-    static String bulkUpdateParamsToString(int bulkUpdateParams) {
+    private static String bulkUpdateParamsToString(int bulkUpdateParams) {
         StringBuilder builder = new StringBuilder(128);
-        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_UPDATE_ROTATION) != 0) {
             builder.append(" UPDATE_ROTATION");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_WALLPAPER_MAY_CHANGE) != 0) {
             builder.append(" WALLPAPER_MAY_CHANGE");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_FORCE_HIDING_CHANGED) != 0) {
             builder.append(" FORCE_HIDING_CHANGED");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE) != 0) {
             builder.append(" ORIENTATION_CHANGE_COMPLETE");
         }
-        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
+        if ((bulkUpdateParams & WindowSurfacePlacer.SET_TURN_ON_SCREEN) != 0) {
             builder.append(" TURN_ON_SCREEN");
         }
         return builder.toString();
@@ -846,7 +850,8 @@
             if (displayId == windows.get(i).getDisplayId()) {
                 setPendingLayoutChanges(displayId, changes);
                 if (WindowManagerService.DEBUG_LAYOUT_REPEATS) {
-                    mService.debugLayoutRepeats(reason, getPendingLayoutChanges(displayId));
+                    mService.mWindowPlacerLocked.debugLayoutRepeats(reason,
+                            getPendingLayoutChanges(displayId));
                 }
                 break;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf690a5..ebabc52 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -34,8 +34,6 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-import android.graphics.Canvas;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -70,7 +68,6 @@
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
-import android.util.IntArray;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
@@ -112,7 +109,6 @@
 import android.view.WindowManagerPolicy;
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
-import android.view.animation.AnimationUtils;
 
 import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 import com.android.internal.app.IAssistScreenshotReceiver;
@@ -157,16 +153,12 @@
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
-import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST;
 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
@@ -177,11 +169,8 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -313,6 +302,7 @@
             }
         }
     };
+    final WindowSurfacePlacer mWindowPlacerLocked;
 
     /**
      * Current user when multi-user is enabled. Don't show windows of
@@ -341,8 +331,6 @@
 
     final IActivityManager mActivityManager;
 
-    final IBatteryStats mBatteryStats;
-
     final AppOpsManager mAppOps;
 
     final DisplaySettings mDisplaySettings;
@@ -444,7 +432,6 @@
 
     final float[] mTmpFloats = new float[9];
     final Rect mTmpContentRect = new Rect();
-    private final Rect mTmpStartRect = new Rect();
 
     boolean mDisplayReady;
     boolean mSafeMode;
@@ -491,7 +478,7 @@
     final static int WINDOWS_FREEZING_SCREENS_NONE = 0;
     final static int WINDOWS_FREEZING_SCREENS_ACTIVE = 1;
     final static int WINDOWS_FREEZING_SCREENS_TIMEOUT = 2;
-    private int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+    int mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
 
     boolean mClientFreezingScreen = false;
     int mAppsFreezingScreen = 0;
@@ -614,51 +601,11 @@
     // For frozen screen animations.
     int mExitAnimId, mEnterAnimId;
 
-    /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple
-     * methods. */
-    class LayoutFields {
-        static final int SET_UPDATE_ROTATION                = 1 << 0;
-        static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
-        static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
-        static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
-        static final int SET_TURN_ON_SCREEN                 = 1 << 4;
-        static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
-
-        boolean mWallpaperForceHidingChanged = false;
-        boolean mWallpaperMayChange = false;
-        boolean mOrientationChangeComplete = true;
-        Object mLastWindowFreezeSource = null;
-        private Session mHoldScreen = null;
-        private boolean mObscured = false;
-        private boolean mSyswin = false;
-        private float mScreenBrightness = -1;
-        private float mButtonBrightness = -1;
-        private long mUserActivityTimeout = -1;
-        private boolean mUpdateRotation = false;
-        boolean mWallpaperActionPending = false;
-
-        // Set to true when the display contains content to show the user.
-        // When false, the display manager may choose to mirror or blank the display.
-        boolean mDisplayHasContent = false;
-
-        // Only set while traversing the default display based on its content.
-        // Affects the behavior of mirroring on secondary displays.
-        boolean mObscureApplicationContentOnSecondaryDisplays = false;
-
-        float mPreferredRefreshRate = 0;
-
-        int mPreferredModeId = 0;
-    }
-    final LayoutFields mInnerFields = new LayoutFields();
-
     boolean mAnimationScheduled;
 
     /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this
      * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */
-    private int mTransactionSequence;
-
-    /** Only do a maximum of 6 repeated layouts. After that quit */
-    private int mLayoutRepeatCount;
+    int mTransactionSequence;
 
     final WindowAnimator mAnimator;
 
@@ -768,7 +715,7 @@
     boolean mInTouchMode;
 
     private ViewServer mViewServer;
-    private final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
+    final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
     boolean mWindowsChanged = false;
 
     public interface WindowChangeListener {
@@ -788,7 +735,7 @@
 
     // List of clients without a transtiton animation that we notify once we are done transitioning
     // since they won't be notified through the app window animator.
-    private final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
+    final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
     /** Listener to notify activity manager about app transitions. */
     private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
@@ -866,6 +813,9 @@
         mDisplaySettings = new DisplaySettings();
         mDisplaySettings.readSettingsLocked();
 
+        mWallpaperControllerLocked = new WallpaperController(this);
+        mWindowPlacerLocked = new WindowSurfacePlacer(this);
+
         LocalServices.addService(WindowManagerPolicy.class, mPolicy);
 
         mPointerEventDispatcher = new PointerEventDispatcher(mInputManager.monitorInput(TAG));
@@ -902,7 +852,6 @@
         mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
 
         mActivityManager = ActivityManagerNative.getDefault();
-        mBatteryStats = BatteryStatsService.getService();
         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
         AppOpsManager.OnOpChangedInternalListener opListener =
                 new AppOpsManager.OnOpChangedInternalListener() {
@@ -953,8 +902,6 @@
 
         updateCircularDisplayMaskIfNeeded();
         showEmulatorDisplayOverlayIfNeeded();
-
-        mWallpaperControllerLocked = new WallpaperController(this);
     }
 
     public InputMonitor getInputMonitor() {
@@ -2118,6 +2065,15 @@
         // If the display is frozen, just remove immediately, since the
         // animation wouldn't be seen.
         if (win.mHasSurface && okToDisplay()) {
+            final AppWindowToken appToken = win.mAppToken;
+            if (appToken != null && appToken.mReplacingWindow) {
+                // This window is going to be replaced. We need to kepp it around until the new one
+                // gets added, then we will get rid of this one.
+                if (DEBUG_ADD_REMOVE) Slog.v(TAG, "Preserving " + win + " until the new one is "
+                        + "added");
+                win.mExiting = true;
+                return;
+            }
             // If we are not currently running the exit animation, we
             // need to see about starting one.
             wasVisible = win.isWinVisibleLw();
@@ -2137,7 +2093,6 @@
                     mAccessibilityController.onWindowTransitionLocked(win, transit);
                 }
             }
-            final AppWindowToken appToken = win.mAppToken;
             final boolean isAnimating = win.mWinAnimator.isAnimating();
             // The starting window is the last window in this app token and it isn't animating.
             // Allow it to be removed now as there is no additional window or animation that will
@@ -2154,7 +2109,7 @@
                 }
                 final boolean focusChanged = updateFocusedWindowLocked(
                         UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
                 if (appToken != null) {
                     appToken.updateReportedVisibilityLocked();
                 }
@@ -2177,6 +2132,10 @@
     }
 
     void removeWindowInnerLocked(WindowState win) {
+        removeWindowInnerLocked(win, true);
+    }
+
+    void removeWindowInnerLocked(WindowState win, boolean performLayout) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2268,13 +2227,15 @@
         final WindowList windows = win.getWindowList();
         if (windows != null) {
             windows.remove(win);
-            if (!mInLayout) {
+            if (!mWindowPlacerLocked.isInLayout()) {
                 assignLayersLocked(windows);
                 final DisplayContent displayContent = win.getDisplayContent();
                 if (displayContent != null) {
                     displayContent.layoutNeeded = true;
                 }
-                performLayoutAndPlaceSurfacesLocked();
+                if (performLayout) {
+                    mWindowPlacerLocked.performSurfacePlacement();
+                }
                 if (win.mAppToken != null) {
                     win.mAppToken.updateReportedVisibilityLocked();
                 }
@@ -2357,7 +2318,7 @@
                     if (displayContent != null) {
                         displayContent.layoutNeeded = true;
                     }
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
             }
         } finally {
@@ -2686,7 +2647,7 @@
             }
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
             if (toBeDisplayed && win.mIsWallpaper) {
                 DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
                 mWallpaperControllerLocked.updateWallpaperOffset(
@@ -3019,7 +2980,7 @@
                     wtoken.hidden = true;
 
                     if (changed) {
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                         updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
                                 false /*updateInputWindows*/);
                     }
@@ -3041,8 +3002,8 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    private Task createTaskLocked(
-            int taskId, int stackId, int userId, AppWindowToken atoken, Rect bounds) {
+    private Task createTaskLocked(int taskId, int stackId, int userId, AppWindowToken atoken,
+            Rect bounds, Configuration config) {
         if (DEBUG_STACK) Slog.i(TAG, "createTaskLocked: taskId=" + taskId + " stackId=" + stackId
                 + " atoken=" + atoken + " bounds=" + bounds);
         final TaskStack stack = mStackIdToStack.get(stackId);
@@ -3050,17 +3011,17 @@
             throw new IllegalArgumentException("addAppToken: invalid stackId=" + stackId);
         }
         EventLog.writeEvent(EventLogTags.WM_TASK_CREATED, taskId, stackId);
-        Task task = new Task(taskId, stack, userId, this, bounds);
+        Task task = new Task(taskId, stack, userId, this, bounds, config);
         mTaskIdToTask.put(taskId, task);
         stack.addTask(task, !atoken.mLaunchTaskBehind /* toTop */, atoken.showForAllUsers);
         return task;
     }
 
     @Override
-    public Configuration addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
+    public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds) {
+            Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3084,7 +3045,7 @@
             AppWindowToken atoken = findAppWindowToken(token.asBinder());
             if (atoken != null) {
                 Slog.w(TAG, "Attempted to add existing app token: " + token);
-                return null;
+                return;
             }
             atoken = new AppWindowToken(this, token, voiceInteraction);
             atoken.inputDispatchingTimeoutNanos = inputDispatchingTimeoutNanos;
@@ -3098,10 +3059,8 @@
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
             Task task = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (task == null) {
-                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds);
-                outConfig = task.mOverrideConfig;
+                task = createTaskLocked(taskId, stackId, userId, atoken, taskBounds, config);
             }
             task.addAppToken(addPos, atoken);
 
@@ -3110,13 +3069,11 @@
             // Application tokens start out hidden.
             atoken.hidden = true;
             atoken.hiddenRequested = true;
-
-            return outConfig;
         }
     }
 
     @Override
-    public Configuration setAppTask(IBinder token, int taskId, Rect taskBounds) {
+    public void setAppTask(IBinder token, int taskId, Rect taskBounds, Configuration config) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "setAppTask()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3126,20 +3083,18 @@
             final AppWindowToken atoken = findAppWindowToken(token);
             if (atoken == null) {
                 Slog.w(TAG, "Attempted to set task id of non-existing app token: " + token);
-                return null;
+                return;
             }
             final Task oldTask = atoken.mTask;
             oldTask.removeAppToken(atoken);
 
             Task newTask = mTaskIdToTask.get(taskId);
-            Configuration outConfig = null;
             if (newTask == null) {
                 newTask = createTaskLocked(
-                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds);
-                outConfig = newTask.mOverrideConfig;
+                        taskId, oldTask.mStack.mStackId, oldTask.mUserId, atoken, taskBounds,
+                        config);
             }
             newTask.addAppToken(Integer.MAX_VALUE /* at top */, atoken);
-            return outConfig;
         }
     }
 
@@ -3391,7 +3346,7 @@
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -3589,7 +3544,7 @@
                 mAppTransition.setReady();
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 } finally {
                     Binder.restoreCallingIdentity(origId);
                 }
@@ -3696,7 +3651,7 @@
                         updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                                 true /*updateInputWindows*/);
                         getDefaultDisplayContentLocked().layoutNeeded = true;
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                         Binder.restoreCallingIdentity(origId);
                         return;
                     } else if (ttoken.startingData != null) {
@@ -3962,7 +3917,7 @@
                 if (performLayout) {
                     updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
                             false /*updateInputWindows*/);
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
                 mInputMonitor.updateInputWindowsLw(false /*force*/);
             }
@@ -4100,7 +4055,7 @@
                             && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
                         if (DEBUG_ORIENTATION) Slog.v(TAG, "set mOrientationChanging of " + w);
                         w.mOrientationChanging = true;
-                        mInnerFields.mOrientationChangeComplete = false;
+                        mWindowPlacerLocked.mOrientationChangeComplete = false;
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
@@ -4120,7 +4075,7 @@
             }
             if (unfreezeSurfaceNow) {
                 if (unfrozeWindows) {
-                    performLayoutAndPlaceSurfacesLocked();
+                    mWindowPlacerLocked.performSurfacePlacement();
                 }
                 stopFreezingDisplayLocked();
             }
@@ -4408,7 +4363,7 @@
         }
 
         mInputMonitor.setUpdateInputWindowsNeededLw();
-        performLayoutAndPlaceSurfacesLocked();
+        mWindowPlacerLocked.performSurfacePlacement();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
 
         //dump();
@@ -4531,7 +4486,9 @@
     }
 
     public void removeStack(int stackId) {
-        mStackIdToStack.remove(stackId);
+        synchronized (mWindowMap) {
+            mStackIdToStack.remove(stackId);
+        }
     }
 
     public void removeTask(int taskId) {
@@ -4558,7 +4515,7 @@
             stack.addTask(task, toTop);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4579,7 +4536,7 @@
             task.moveTaskToStack(stack, toTop);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4599,22 +4556,22 @@
      * @param stackId Id of stack to resize.
      * @param bounds New stack bounds. Passing in null sets the bounds to fullscreen.
      * @param resizeTasks If true, the tasks within the stack will also be resized.
-     * @param changedTaskIds Output list of Ids of tasks that changed in bounds due to resize.
-     * @param newTaskConfigs Output list of new Configuation of the tasks that changed.
+     * @param configs Configurations for tasks in the resized stack, keyed by task id.
+     * @param taskBounds Bounds for tasks in the resized stack, keyed by task id.
      * @return True if the stack is now fullscreen.
      * */
     public boolean resizeStack(int stackId, Rect bounds, boolean resizeTasks,
-            IntArray changedTaskIds, List<Configuration> newTaskConfigs) {
+            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, resizeTasks, changedTaskIds, newTaskConfigs)) {
+            if (stack.setBounds(bounds, resizeTasks, configs, taskBounds)) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
             }
             return stack.isFullscreen();
         }
@@ -4639,7 +4596,7 @@
             task.positionTaskInStack(stack, position);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.layoutNeeded = true;
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -4648,19 +4605,20 @@
      * Returns a {@link Configuration} object that contains configurations settings
      * that should be overridden due to the operation.
      */
-    public Configuration resizeTask(int taskId, Rect bounds) {
+    public void resizeTask(int taskId, Rect bounds, Configuration configuration, boolean relayout) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
             if (task == null) {
                 throw new IllegalArgumentException("resizeTask: taskId " + taskId
                         + " not found.");
             }
-            if (task.setBounds(bounds)) {
+            if (task.setBounds(bounds, configuration)) {
                 task.resizeWindows();
-                task.getDisplayContent().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                if (relayout) {
+                    task.getDisplayContent().layoutNeeded = true;
+                    mWindowPlacerLocked.performSurfacePlacement();
+                }
             }
-            return new Configuration(task.mOverrideConfig);
         }
     }
 
@@ -5051,7 +5009,7 @@
                 displayContent.switchUserStacks();
                 rebuildAppWindowListLocked(displayContent);
             }
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -5890,7 +5848,7 @@
             changed = updateRotationUncheckedLocked(false);
             if (!changed || forceRelayout) {
                 getDefaultDisplayContentLocked().layoutNeeded = true;
-                performLayoutAndPlaceSurfacesLocked();
+                mWindowPlacerLocked.performSurfacePlacement();
             }
         }
 
@@ -6024,7 +5982,7 @@
             if (w.mHasSurface) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Set mOrientationChanging of " + w);
                 w.mOrientationChanging = true;
-                mInnerFields.mOrientationChangeComplete = false;
+                mWindowPlacerLocked.mOrientationChangeComplete = false;
             }
             w.mLastFreezeDuration = 0;
         }
@@ -7175,7 +7133,7 @@
                 case DO_TRAVERSAL: {
                     synchronized(mWindowMap) {
                         mTraversalScheduled = false;
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                     }
                 } break;
 
@@ -7347,7 +7305,7 @@
                                 Slog.w(TAG, "Force clearing orientation change: " + w);
                             }
                         }
-                        performLayoutAndPlaceSurfacesLocked();
+                        mWindowPlacerLocked.performSurfacePlacement();
                     }
                     break;
                 }
@@ -7361,7 +7319,7 @@
                                     + " mOpeningApps.size()=" + mOpeningApps.size()
                                     + " mClosingApps.size()=" + mClosingApps.size());
                             mAppTransition.setTimeout();
-                            performLayoutAndPlaceSurfacesLocked();
+                            mWindowPlacerLocked.performSurfacePlacement();
                         }
                     }
                     break;
@@ -7624,7 +7582,7 @@
                 case WALLPAPER_DRAW_PENDING_TIMEOUT: {
                     synchronized (mWindowMap) {
                         if (mWallpaperControllerLocked.processWallpaperDrawPendingTimeout()) {
-                            performLayoutAndPlaceSurfacesLocked();
+                            mWindowPlacerLocked.performSurfacePlacement();
                         }
                     }
                 }
@@ -8016,7 +7974,7 @@
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
         }
 
-        performLayoutAndPlaceSurfacesLocked();
+        mWindowPlacerLocked.performSurfacePlacement();
     }
 
     private void configureDisplayPolicyLocked(DisplayContent displayContent) {
@@ -8204,7 +8162,7 @@
         Arrays.fill(mRebuildTmp, null);
     }
 
-    private final void assignLayersLocked(WindowList windows) {
+    final void assignLayersLocked(WindowList windows) {
         int N = windows.size();
         int curBaseLayer = 0;
         int curLayer = 0;
@@ -8274,253 +8232,6 @@
         }
     }
 
-    private final void performLayoutAndPlaceSurfacesLocked() {
-        int loopCount = 6;
-        do {
-            mTraversalScheduled = false;
-            performLayoutAndPlaceSurfacesLockedLoop();
-            mH.removeMessages(H.DO_TRAVERSAL);
-            loopCount--;
-        } while (mTraversalScheduled && loopCount > 0);
-        mInnerFields.mWallpaperActionPending = false;
-    }
-
-    private boolean mInLayout = false;
-    private final void performLayoutAndPlaceSurfacesLockedLoop() {
-        if (mInLayout) {
-            if (DEBUG) {
-                throw new RuntimeException("Recursive call!");
-            }
-            Slog.w(TAG, "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
-                    + Debug.getCallers(3));
-            return;
-        }
-
-        if (mWaitingForConfig) {
-            // Our configuration has changed (most likely rotation), but we
-            // don't yet have the complete configuration to report to
-            // applications.  Don't do any window layout until we have it.
-            return;
-        }
-
-        if (!mDisplayReady) {
-            // Not yet initialized, nothing to do.
-            return;
-        }
-
-        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
-        mInLayout = true;
-
-        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) {
-                }
-            }
-        }
-
-        try {
-            performLayoutAndPlaceSurfacesLockedInner(recoveringMemory);
-
-            mInLayout = false;
-
-            if (needsLayout()) {
-                if (++mLayoutRepeatCount < 6) {
-                    requestTraversalLocked();
-                } else {
-                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
-                    mLayoutRepeatCount = 0;
-                }
-            } else {
-                mLayoutRepeatCount = 0;
-            }
-
-            if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) {
-                mH.removeMessages(H.REPORT_WINDOWS_CHANGE);
-                mH.sendEmptyMessage(H.REPORT_WINDOWS_CHANGE);
-            }
-        } catch (RuntimeException e) {
-            mInLayout = false;
-            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
-        }
-
-        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
-    }
-
-    private final void performLayoutLockedInner(final DisplayContent displayContent,
-                                    boolean initial, boolean updateInputWindows) {
-        if (!displayContent.layoutNeeded) {
-            return;
-        }
-        displayContent.layoutNeeded = false;
-        WindowList windows = displayContent.getWindowList();
-        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
-
-        DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
-
-        if (mInputConsumer != null) {
-            mInputConsumer.layout(dw, dh);
-        }
-
-        final int N = windows.size();
-        int i;
-
-        if (DEBUG_LAYOUT) {
-            Slog.v(TAG, "-------------------------------------");
-            Slog.v(TAG, "performLayout: needed="
-                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
-        }
-
-        mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation);
-        if (isDefaultDisplay) {
-            // Not needed on non-default displays.
-            mSystemDecorLayer = mPolicy.getSystemDecorLayerLw();
-            mScreenRect.set(0, 0, dw, dh);
-        }
-
-        mPolicy.getContentRectLw(mTmpContentRect);
-        displayContent.resize(mTmpContentRect);
-
-        int seq = mLayoutSeq+1;
-        if (seq < 0) seq = 0;
-        mLayoutSeq = seq;
-
-        boolean behindDream = false;
-
-        // First perform layout of any root windows (not attached
-        // to another window).
-        int topAttached = -1;
-        for (i = N-1; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-
-            // Don't do layout of a window if it is not visible, or
-            // soon won't be visible, to avoid wasting time and funky
-            // changes while a window is animating away.
-            final boolean gone = (behindDream && mPolicy.canBeForceHidden(win, win.mAttrs))
-                    || win.isGoneForLayoutLw();
-
-            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
-                Slog.v(TAG, "1ST PASS " + win
-                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
-                        + " mLayoutAttached=" + win.mLayoutAttached
-                        + " screen changed=" + win.isConfigChanged());
-                final AppWindowToken atoken = win.mAppToken;
-                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
-                        + win.mViewVisibility + " mRelayoutCalled="
-                        + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
-                        + (atoken != null && atoken.hiddenRequested)
-                        + " mAttachedHidden=" + win.mAttachedHidden);
-                else Slog.v(TAG, "  VIS: mViewVisibility="
-                        + win.mViewVisibility + " mRelayoutCalled="
-                        + win.mRelayoutCalled + " hidden="
-                        + win.mRootToken.hidden + " hiddenRequested="
-                        + (atoken != null && atoken.hiddenRequested)
-                        + " mAttachedHidden=" + win.mAttachedHidden);
-            }
-
-            // If this view is GONE, then skip it -- keep the current
-            // frame, and let the caller know so they can ignore it
-            // if they want.  (We do the normal layout for INVISIBLE
-            // windows, since that means "perform layout as normal,
-            // just don't display").
-            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
-                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
-                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
-                            (win.mHasSurface && win.mAppToken != null &&
-                            win.mAppToken.layoutConfigChanges)))) {
-                if (!win.mLayoutAttached) {
-                    if (initial) {
-                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                        win.mContentChanged = false;
-                    }
-                    if (win.mAttrs.type == TYPE_DREAM) {
-                        // Don't layout windows behind a dream, so that if it
-                        // does stuff like hide the status bar we won't get a
-                        // bad transition when it goes away.
-                        behindDream = true;
-                    }
-                    win.mLayoutNeeded = false;
-                    win.prelayout();
-                    mPolicy.layoutWindowLw(win, null);
-                    win.mLayoutSeq = seq;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
-                            + win.mFrame + " mContainingFrame="
-                            + win.mContainingFrame + " mDisplayFrame="
-                            + win.mDisplayFrame);
-                } else {
-                    if (topAttached < 0) topAttached = i;
-                }
-            }
-        }
-
-        boolean attachedBehindDream = false;
-
-        // Now perform layout of attached windows, which usually
-        // depend on the position of the window they are attached to.
-        // XXX does not deal with windows that are attached to windows
-        // that are themselves attached.
-        for (i = topAttached; i >= 0; i--) {
-            final WindowState win = windows.get(i);
-
-            if (win.mLayoutAttached) {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "2ND PASS " + win
-                        + " mHaveFrame=" + win.mHaveFrame
-                        + " mViewVisibility=" + win.mViewVisibility
-                        + " mRelayoutCalled=" + win.mRelayoutCalled);
-                // If this view is GONE, then skip it -- keep the current
-                // frame, and let the caller know so they can ignore it
-                // if they want.  (We do the normal layout for INVISIBLE
-                // windows, since that means "perform layout as normal,
-                // just don't display").
-                if (attachedBehindDream && mPolicy.canBeForceHidden(win, win.mAttrs)) {
-                    continue;
-                }
-                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
-                        || !win.mHaveFrame || win.mLayoutNeeded) {
-                    if (initial) {
-                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
-                        win.mContentChanged = false;
-                    }
-                    win.mLayoutNeeded = false;
-                    win.prelayout();
-                    mPolicy.layoutWindowLw(win, win.mAttachedWindow);
-                    win.mLayoutSeq = seq;
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "  LAYOUT: mFrame="
-                            + win.mFrame + " mContainingFrame="
-                            + win.mContainingFrame + " mDisplayFrame="
-                            + win.mDisplayFrame);
-                }
-            } else if (win.mAttrs.type == TYPE_DREAM) {
-                // Don't layout windows behind a dream, so that if it
-                // does stuff like hide the status bar we won't get a
-                // bad transition when it goes away.
-                attachedBehindDream = behindDream;
-            }
-        }
-
-        // Window frames may have changed.  Tell the input dispatcher about it.
-        mInputMonitor.setUpdateInputWindowsNeededLw();
-        if (updateInputWindows) {
-            mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-
-        mPolicy.finishLayoutLw();
-    }
-
     void makeWindowFreezingScreenIfNeededLocked(WindowState w) {
         // If the screen is currently frozen or off, then keep
         // it frozen/off until this window draws at its new
@@ -8529,7 +8240,7 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w);
             w.mOrientationChanging = true;
             w.mLastFreezeDuration = 0;
-            mInnerFields.mOrientationChangeComplete = false;
+            mWindowPlacerLocked.mOrientationChangeComplete = false;
             if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
                 mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
                 // XXX should probably keep timeout from
@@ -8542,411 +8253,9 @@
     }
 
     /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @param windows List of windows on default display.
      * @return bitmap indicating if another pass through layout must be made.
      */
-    public int handleAppTransitionReadyLocked(WindowList windows) {
-        int appsCount = mOpeningApps.size();
-        if (!checkIfTransitionGoodToGo(appsCount)) {
-            return 0;
-        }
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
-        int transit = mAppTransition.getAppTransition();
-        if (mSkipAppTransitionAnimation) {
-            transit = AppTransition.TRANSIT_UNSET;
-        }
-        mSkipAppTransitionAnimation = false;
-        mNoAnimationNotifyOnTransitionFinished.clear();
-
-        mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
-
-        rebuildAppWindowListLocked();
-
-        mInnerFields.mWallpaperMayChange = false;
-
-        // The top-most window will supply the layout params,
-        // and we will determine it below.
-        LayoutParams animLp = null;
-        int bestAnimLayer = -1;
-        boolean fullscreenAnim = false;
-        boolean voiceInteraction = false;
-
-        final WindowState lowerWallpaperTarget =
-                mWallpaperControllerLocked.getLowerWallpaperTarget();
-        final WindowState upperWallpaperTarget =
-                mWallpaperControllerLocked.getUpperWallpaperTarget();
-
-        boolean openingAppHasWallpaper = false;
-        boolean closingAppHasWallpaper = false;
-        final AppWindowToken lowerWallpaperAppToken;
-        final AppWindowToken upperWallpaperAppToken;
-        if (lowerWallpaperTarget == null) {
-            lowerWallpaperAppToken = upperWallpaperAppToken = null;
-        } else {
-            lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
-            upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
-        }
-
-        int i;
-        // Do a first pass through the tokens for two
-        // things:
-        // (1) Determine if both the closing and opening
-        // app token sets are wallpaper targets, in which
-        // case special animations are needed
-        // (since the wallpaper needs to stay static
-        // behind them).
-        // (2) Find the layout params of the top-most
-        // application window in the tokens, which is
-        // what will control the animation theme.
-        final int closingAppsCount = mClosingApps.size();
-        appsCount = closingAppsCount + mOpeningApps.size();
-        for (i = 0; i < appsCount; i++) {
-            final AppWindowToken wtoken;
-            if (i < closingAppsCount) {
-                wtoken = mClosingApps.valueAt(i);
-                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
-                    closingAppHasWallpaper = true;
-                }
-            } else {
-                wtoken = mOpeningApps.valueAt(i - closingAppsCount);
-                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
-                    openingAppHasWallpaper = true;
-                }
-            }
-
-            voiceInteraction |= wtoken.voiceInteraction;
-
-            if (wtoken.appFullscreen) {
-                WindowState ws = wtoken.findMainWindow();
-                if (ws != null) {
-                    animLp = ws.mAttrs;
-                    bestAnimLayer = ws.mLayer;
-                    fullscreenAnim = true;
-                }
-            } else if (!fullscreenAnim) {
-                WindowState ws = wtoken.findMainWindow();
-                if (ws != null) {
-                    if (ws.mLayer > bestAnimLayer) {
-                        animLp = ws.mAttrs;
-                        bestAnimLayer = ws.mLayer;
-                    }
-                }
-            }
-        }
-
-        transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
-                closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
-
-        // If all closing windows are obscured, then there is
-        // no need to do an animation.  This is the case, for
-        // example, when this transition is being done behind
-        // the lock screen.
-        if (!mPolicy.allowAppAnimationsLw()) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "Animations disallowed by keyguard or dream.");
-            animLp = null;
-        }
-
-        processApplicationsAnimatingInPlace(transit);
-
-        AppWindowToken topClosingApp = null;
-        int topClosingLayer = 0;
-        appsCount = mClosingApps.size();
-        for (i = 0; i < appsCount; i++) {
-            AppWindowToken wtoken = mClosingApps.valueAt(i);
-            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app " + wtoken);
-            appAnimator.clearThumbnail();
-            appAnimator.animation = null;
-            wtoken.inPendingTransaction = false;
-            setTokenVisibilityLocked(wtoken, animLp, false, transit, false, voiceInteraction);
-            wtoken.updateReportedVisibilityLocked();
-            // Force the allDrawn flag, because we want to start
-            // this guy's animations regardless of whether it's
-            // gotten drawn.
-            wtoken.allDrawn = true;
-            wtoken.deferClearAllDrawn = false;
-            // Ensure that apps that are mid-starting are also scheduled to have their
-            // starting windows removed after the animation is complete
-            if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
-                scheduleRemoveStartingWindowLocked(wtoken);
-            }
-            mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
-            if (animLp != null) {
-                int layer = -1;
-                for (int j = 0; j < wtoken.windows.size(); j++) {
-                    WindowState win = wtoken.windows.get(j);
-                    if (win.mWinAnimator.mAnimLayer > layer) {
-                        layer = win.mWinAnimator.mAnimLayer;
-                    }
-                }
-                if (topClosingApp == null || layer > topClosingLayer) {
-                    topClosingApp = wtoken;
-                    topClosingLayer = layer;
-                }
-            }
-        }
-
-        AppWindowToken topOpeningApp = null;
-        appsCount = mOpeningApps.size();
-        for (i = 0; i < appsCount; i++) {
-            AppWindowToken wtoken = mOpeningApps.valueAt(i);
-            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken);
-
-            if (!appAnimator.usingTransferredAnimation) {
-                appAnimator.clearThumbnail();
-                appAnimator.animation = null;
-            }
-            wtoken.inPendingTransaction = false;
-            if (!setTokenVisibilityLocked(
-                    wtoken, animLp, true, transit, false, voiceInteraction)){
-                // This token isn't going to be animating. Add it to the list of tokens to
-                // be notified of app transition complete since the notification will not be
-                // sent be the app window animator.
-                mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
-            }
-            wtoken.updateReportedVisibilityLocked();
-            wtoken.waitingToShow = false;
-
-            appAnimator.mAllAppWinAnimators.clear();
-            final int windowsCount = wtoken.allAppWindows.size();
-            for (int j = 0; j < windowsCount; j++) {
-                appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
-            }
-            mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
-            mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-
-            int topOpeningLayer = 0;
-            if (animLp != null) {
-                int layer = -1;
-                for (int j = 0; j < wtoken.windows.size(); j++) {
-                    WindowState win = wtoken.windows.get(j);
-                    if (win.mWinAnimator.mAnimLayer > layer) {
-                        layer = win.mWinAnimator.mAnimLayer;
-                    }
-                }
-                if (topOpeningApp == null || layer > topOpeningLayer) {
-                    topOpeningApp = wtoken;
-                    topOpeningLayer = layer;
-                }
-            }
-            createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
-        }
-
-        AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
-                topOpeningApp.mAppAnimator;
-        AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
-                topClosingApp.mAppAnimator;
-
-        mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
-        mAppTransition.postAnimationCallback();
-        mAppTransition.clear();
-
-        mOpeningApps.clear();
-        mClosingApps.clear();
-
-        // This has changed the visibility of windows, so perform
-        // a new layout to get them all up-to-date.
-        getDefaultDisplayContentLocked().layoutNeeded = true;
-
-        // TODO(multidisplay): IMEs are only supported on the default display.
-        if (windows == getDefaultWindowListLocked()
-                && !moveInputMethodWindowsIfNeededLocked(true)) {
-            assignLayersLocked(windows);
-        }
-        updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES, true /*updateInputWindows*/);
-        mFocusMayChange = false;
-        notifyActivityDrawnForKeyguard();
-        return WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
-                | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-
-    }
-
-    private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
-            boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
-            WindowState upperWallpaperTarget) {
-        // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
-        final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
-        final WindowState oldWallpaper = mWallpaperControllerLocked.isWallpaperTargetAnimating()
-                ? null : wallpaperTarget;
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "New wallpaper target=" + wallpaperTarget
-                        + ", oldWallpaper=" + oldWallpaper
-                        + ", lower target=" + lowerWallpaperTarget
-                        + ", upper target=" + upperWallpaperTarget);
-        mAnimateWallpaperWithTarget = false;
-        if (closingAppHasWallpaper && openingAppHasWallpaper) {
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Wallpaper animation!");
-            switch (transit) {
-                case AppTransition.TRANSIT_ACTIVITY_OPEN:
-                case AppTransition.TRANSIT_TASK_OPEN:
-                case AppTransition.TRANSIT_TASK_TO_FRONT:
-                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
-                    break;
-                case AppTransition.TRANSIT_ACTIVITY_CLOSE:
-                case AppTransition.TRANSIT_TASK_CLOSE:
-                case AppTransition.TRANSIT_TASK_TO_BACK:
-                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
-                    break;
-            }
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit: " + AppTransition.appTransitionToString(transit));
-        } else if ((oldWallpaper != null) && !mOpeningApps.isEmpty()
-                && !mOpeningApps.contains(oldWallpaper.mAppToken)) {
-            // We are transitioning from an activity with
-            // a wallpaper to one without.
-            transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit away from wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
-            // We are transitioning from an activity without
-            // a wallpaper to now showing the wallpaper
-            transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New transit into wallpaper: "
-                    + AppTransition.appTransitionToString(transit));
-        } else {
-            mAnimateWallpaperWithTarget = true;
-        }
-        return transit;
-    }
-
-    private void processApplicationsAnimatingInPlace(int transit) {
-        if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
-            // Find the focused window
-            final WindowState win =
-                    findFocusedWindowLocked(getDefaultDisplayContentLocked());
-            if (win != null) {
-                final AppWindowToken wtoken = win.mAppToken;
-                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now animating app in place " + wtoken);
-                appAnimator.clearThumbnail();
-                appAnimator.animation = null;
-                updateTokenInPlaceLocked(wtoken, transit);
-                wtoken.updateReportedVisibilityLocked();
-
-                appAnimator.mAllAppWinAnimators.clear();
-                final int N = wtoken.allAppWindows.size();
-                for (int j = 0; j < N; j++) {
-                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
-                }
-                mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
-                mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
-            }
-        }
-    }
-
-    private boolean checkIfTransitionGoodToGo(int appsCount) {
-        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                "Checking " + appsCount + " opening apps (frozen="
-                        + mDisplayFrozen + " timeout="
-                        + mAppTransition.isTimeout() + ")...");
-        if (!mAppTransition.isTimeout()) {
-            for (int i = 0; i < appsCount; i++) {
-                AppWindowToken wtoken = mOpeningApps.valueAt(i);
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                        "Check opening app=" + wtoken + ": allDrawn="
-                        + wtoken.allDrawn + " startingDisplayed="
-                        + wtoken.startingDisplayed + " startingMoved="
-                        + wtoken.startingMoved);
-                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
-                    return false;
-                }
-            }
-
-            // If the wallpaper is visible, we need to check it's ready too.
-            return !mWallpaperControllerLocked.isWallpaperVisible() ||
-                    mWallpaperControllerLocked.wallpaperTransitionReady();
-        }
-        return true;
-    }
-
-    private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
-            int openingLayer, int closingLayer) {
-        AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
-        if (openingAppAnimator == null || openingAppAnimator.animation == null) {
-            return;
-        }
-        final int taskId = appToken.mTask.mTaskId;
-        Bitmap thumbnailHeader = mAppTransition.getAppTransitionThumbnailHeader(taskId);
-        if (thumbnailHeader == null || thumbnailHeader.getConfig() == Config.ALPHA_8) {
-            return;
-        }
-        // This thumbnail animation is very special, we need to have
-        // an extra surface with the thumbnail included with the animation.
-        Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
-        try {
-            // TODO(multi-display): support other displays
-            final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final Display display = displayContent.getDisplay();
-            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-
-            // Create a new surface for the thumbnail
-            SurfaceControl surfaceControl = new SurfaceControl(mFxSession,
-                    "thumbnail anim", dirty.width(), dirty.height(),
-                    PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
-            surfaceControl.setLayerStack(display.getLayerStack());
-            if (SHOW_TRANSACTIONS) {
-                Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
-            }
-
-            // Draw the thumbnail onto the surface
-            Surface drawSurface = new Surface();
-            drawSurface.copyFrom(surfaceControl);
-            Canvas c = drawSurface.lockCanvas(dirty);
-            c.drawBitmap(thumbnailHeader, 0, 0, null);
-            drawSurface.unlockCanvasAndPost(c);
-            drawSurface.release();
-
-            // Get the thumbnail animation
-            Animation anim;
-            if (mAppTransition.isNextThumbnailTransitionAspectScaled()) {
-                // If this is a multi-window scenario, we use the windows frame as
-                // destination of the thumbnail header animation. If this is a full screen
-                // window scenario, we use the whole display as the target.
-                WindowState win = appToken.findMainWindow();
-                Rect appRect = win != null ? win.getContentFrameLw() :
-                        new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
-                // For the new aspect-scaled transition, we want it to always show
-                // above the animating opening/closing window, and we want to
-                // synchronize its thumbnail surface with the surface for the
-                // open/close animation (only on the way down)
-                anim = mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
-                        thumbnailHeader, taskId);
-                Log.d(TAG, "assigning thumbnail force above layer: " + openingLayer + " " +
-                        closingLayer);
-                openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
-                openingAppAnimator.deferThumbnailDestruction =
-                        !mAppTransition.isNextThumbnailTransitionScaleUp();
-            } else {
-                anim = mAppTransition.createThumbnailScaleAnimationLocked(
-                        displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
-            }
-            anim.restrictDuration(MAX_ANIMATION_DURATION);
-            anim.scaleCurrentDuration(getTransitionAnimationScaleLocked());
-
-            openingAppAnimator.thumbnail = surfaceControl;
-            openingAppAnimator.thumbnailLayer = openingLayer;
-            openingAppAnimator.thumbnailAnimation = anim;
-            mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
-            openingAppAnimator.thumbnailX = mTmpStartRect.left;
-            openingAppAnimator.thumbnailY = mTmpStartRect.top;
-        } catch (OutOfResourcesException e) {
-            Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w=" + dirty.width()
-                    + " h=" + dirty.height(), e);
-            openingAppAnimator.clearThumbnail();
-        }
-    }
-
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @return bitmap indicating if another pass through layout must be made.
-     */
-    private int handleAnimatingStoppedAndTransitionLocked() {
+    int handleAnimatingStoppedAndTransitionLocked() {
         int changes = 0;
 
         mAppTransition.setIdle();
@@ -8976,7 +8285,7 @@
         if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
                 "Wallpaper layer changed: assigning layers + relayout");
         moveInputMethodWindowsIfNeededLocked(true);
-        mInnerFields.mWallpaperMayChange = true;
+        mWindowPlacerLocked.mWallpaperMayChange = true;
         // Since the window list has been rebuilt, focus might
         // have to be recomputed since the actual order of windows
         // might have changed again.
@@ -8985,7 +8294,7 @@
         return changes;
     }
 
-    private void updateResizingWindows(final WindowState w) {
+    void updateResizingWindows(final WindowState w) {
         final WindowStateAnimator winAnimator = w.mWinAnimator;
         if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
             w.setInsetsChanged();
@@ -9057,707 +8366,6 @@
         }
     }
 
-    /**
-     * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     * @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 int innerDw, final int innerDh) {
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        final int attrFlags = attrs.flags;
-        final boolean canBeSeen = w.isDisplayedLw();
-        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
-
-        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
-            // This window completely covers everything behind it,
-            // so we want to leave all of them as undimmed (for
-            // performance reasons).
-            mInnerFields.mObscured = true;
-        }
-
-        if (w.mHasSurface) {
-            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
-                mInnerFields.mHoldScreen = w.mSession;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.screenBrightness >= 0
-                    && mInnerFields.mScreenBrightness < 0) {
-                mInnerFields.mScreenBrightness = w.mAttrs.screenBrightness;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.buttonBrightness >= 0
-                    && mInnerFields.mButtonBrightness < 0) {
-                mInnerFields.mButtonBrightness = w.mAttrs.buttonBrightness;
-            }
-            if (!mInnerFields.mSyswin && w.mAttrs.userActivityTimeout >= 0
-                    && mInnerFields.mUserActivityTimeout < 0) {
-                mInnerFields.mUserActivityTimeout = w.mAttrs.userActivityTimeout;
-            }
-
-            final int type = attrs.type;
-            if (canBeSeen
-                    && (type == TYPE_SYSTEM_DIALOG
-                     || type == TYPE_SYSTEM_ERROR
-                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
-                mInnerFields.mSyswin = true;
-            }
-
-            if (canBeSeen) {
-                // This function assumes that the contents of the default display are
-                // processed first before secondary displays.
-                final DisplayContent displayContent = w.getDisplayContent();
-                if (displayContent != null && displayContent.isDefaultDisplay) {
-                    // While a dream or keyguard is showing, obscure ordinary application
-                    // content on secondary displays (by forcibly enabling mirroring unless
-                    // there is other content we want to show) but still allow opaque
-                    // keyguard dialogs to be shown.
-                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = true;
-                    }
-                    mInnerFields.mDisplayHasContent = true;
-                } else if (displayContent != null &&
-                        (!mInnerFields.mObscureApplicationContentOnSecondaryDisplays
-                        || (mInnerFields.mObscured && type == TYPE_KEYGUARD_DIALOG))) {
-                    // Allow full screen keyguard presentation dialogs to be seen.
-                    mInnerFields.mDisplayHasContent = true;
-                }
-                if (mInnerFields.mPreferredRefreshRate == 0
-                        && w.mAttrs.preferredRefreshRate != 0) {
-                    mInnerFields.mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
-                }
-                if (mInnerFields.mPreferredModeId == 0
-                        && w.mAttrs.preferredDisplayModeId != 0) {
-                    mInnerFields.mPreferredModeId = w.mAttrs.preferredDisplayModeId;
-                }
-            }
-        }
-    }
-
-    private void handleFlagDimBehind(WindowState w) {
-        final WindowManager.LayoutParams attrs = w.mAttrs;
-        if ((attrs.flags & FLAG_DIM_BEHIND) != 0
-                && w.isDisplayedLw()
-                && !w.mExiting) {
-            final WindowStateAnimator winAnimator = w.mWinAnimator;
-            final Task task = w.getTask();
-            if (task == null) {
-                return;
-            }
-            task.setContinueDimming();
-            if (!task.isDimming(winAnimator)) {
-                if (localLOGV) Slog.v(TAG, "Win " + w + " start dimming.");
-                task.startDimmingIfNeeded(winAnimator);
-            }
-        }
-    }
-
-    private void updateAllDrawnLocked(DisplayContent displayContent) {
-        // See if any windows have been drawn, so they (and others
-        // associated with them) can now be shown.
-        ArrayList<TaskStack> stacks = displayContent.getStacks();
-        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
-            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
-                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                    final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (!wtoken.allDrawn) {
-                        int numInteresting = wtoken.numInterestingWindows;
-                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
-                            if (DEBUG_VISIBILITY) Slog.v(TAG,
-                                    "allDrawn: " + wtoken
-                                    + " interesting=" + numInteresting
-                                    + " drawn=" + wtoken.numDrawnWindows);
-                            wtoken.allDrawn = true;
-                            // Force an additional layout pass where WindowStateAnimator#
-                            // commitFinishDrawingLocked() will call performShowLocked().
-                            displayContent.layoutNeeded = true;
-                            mH.obtainMessage(H.NOTIFY_ACTIVITY_DRAWN, wtoken.token).sendToTarget();
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // "Something has changed!  Let's make it correct now."
-    private final void performLayoutAndPlaceSurfacesLockedInner(boolean recoveringMemory) {
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.v(TAG, "performLayoutAndPlaceSurfacesLockedInner: entry. Called by "
-                    + Debug.getCallers(3));
-        }
-
-        int i;
-        boolean updateInputWindowsNeeded = false;
-
-        if (mFocusMayChange) {
-            mFocusMayChange = false;
-            updateInputWindowsNeeded = updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES,
-                    false /*updateInputWindows*/);
-        }
-
-        // Initialize state of exiting tokens.
-        final int numDisplays = mDisplayContents.size();
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
-                displayContent.mExitingTokens.get(i).hasVisible = false;
-            }
-        }
-
-        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
-                exitingAppTokens.get(tokenNdx).hasVisible = false;
-            }
-        }
-
-        mInnerFields.mHoldScreen = null;
-        mInnerFields.mScreenBrightness = -1;
-        mInnerFields.mButtonBrightness = -1;
-        mInnerFields.mUserActivityTimeout = -1;
-        mInnerFields.mObscureApplicationContentOnSecondaryDisplays = false;
-
-        mTransactionSequence++;
-
-        final DisplayContent defaultDisplay = getDefaultDisplayContentLocked();
-        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
-        final int defaultDw = defaultInfo.logicalWidth;
-        final int defaultDh = defaultInfo.logicalHeight;
-
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
-        SurfaceControl.openTransaction();
-        try {
-
-            if (mWatermark != null) {
-                mWatermark.positionSurface(defaultDw, defaultDh);
-            }
-            if (mStrictModeFlash != null) {
-                mStrictModeFlash.positionSurface(defaultDw, defaultDh);
-            }
-            if (mCircularDisplayMask != null) {
-                mCircularDisplayMask.positionSurface(defaultDw, defaultDh, mRotation);
-            }
-            if (mEmulatorDisplayOverlay != null) {
-                mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh, mRotation);
-            }
-
-            boolean focusDisplayed = false;
-
-            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-                final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-                boolean updateAllDrawn = false;
-                WindowList windows = displayContent.getWindowList();
-                DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                final int displayId = displayContent.getDisplayId();
-                final int dw = displayInfo.logicalWidth;
-                final int dh = displayInfo.logicalHeight;
-                final int innerDw = displayInfo.appWidth;
-                final int innerDh = displayInfo.appHeight;
-                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-
-                // Reset for each display.
-                mInnerFields.mDisplayHasContent = false;
-                mInnerFields.mPreferredRefreshRate = 0;
-                mInnerFields.mPreferredModeId = 0;
-
-                int repeats = 0;
-                do {
-                    repeats++;
-                    if (repeats > 6) {
-                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
-                        displayContent.layoutNeeded = false;
-                        break;
-                    }
-
-                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner",
-                        displayContent.pendingLayoutChanges);
-
-                    if ((displayContent.pendingLayoutChanges &
-                            WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                            mWallpaperControllerLocked.adjustWallpaperWindows()) {
-                        assignLayersLocked(windows);
-                        displayContent.layoutNeeded = true;
-                    }
-
-                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
-                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                        if (updateOrientationFromAppTokensLocked(true)) {
-                            displayContent.layoutNeeded = true;
-                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                        }
-                    }
-
-                    if ((displayContent.pendingLayoutChanges
-                            & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
-                        displayContent.layoutNeeded = true;
-                    }
-
-                    // FIRST LOOP: Perform a layout, if needed.
-                    if (repeats < LAYOUT_REPEAT_THRESHOLD) {
-                        performLayoutLockedInner(displayContent, repeats == 1,
-                                false /*updateInputWindows*/);
-                    } else {
-                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
-                    }
-
-                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
-                    // it is animating.
-                    displayContent.pendingLayoutChanges = 0;
-
-                    if (isDefaultDisplay) {
-                        mPolicy.beginPostLayoutPolicyLw(dw, dh);
-                        for (i = windows.size() - 1; i >= 0; i--) {
-                            WindowState w = windows.get(i);
-                            if (w.mHasSurface) {
-                                mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs, w.mAttachedWindow);
-                            }
-                        }
-                        displayContent.pendingLayoutChanges |= mPolicy.finishPostLayoutPolicyLw();
-                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
-                            "after finishPostLayoutPolicyLw", displayContent.pendingLayoutChanges);
-                    }
-                } while (displayContent.pendingLayoutChanges != 0);
-
-                mInnerFields.mObscured = false;
-                mInnerFields.mSyswin = false;
-                displayContent.resetDimming();
-
-                // Only used if default window
-                final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
-
-                final int N = windows.size();
-                for (i=N-1; i>=0; i--) {
-                    WindowState w = windows.get(i);
-                    final Task task = w.getTask();
-                    if (task == null && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
-                        continue;
-                    }
-
-                    final boolean obscuredChanged = w.mObscured != mInnerFields.mObscured;
-
-                    // Update effect.
-                    w.mObscured = mInnerFields.mObscured;
-                    if (!mInnerFields.mObscured) {
-                        handleNotObscuredLocked(w, innerDw, innerDh);
-                    }
-
-                    if (task != null && !task.getContinueDimming()) {
-                        handleFlagDimBehind(w);
-                    }
-
-                    if (isDefaultDisplay && obscuredChanged
-                            && mWallpaperControllerLocked.isWallpaperTarget(w) && w.isVisibleLw()) {
-                        // This is the wallpaper target and its obscured state
-                        // changed... make sure the current wallaper's visibility
-                        // has been updated accordingly.
-                        mWallpaperControllerLocked.updateWallpaperVisibility();
-                    }
-
-                    final WindowStateAnimator winAnimator = w.mWinAnimator;
-
-                    // If the window has moved due to its containing content frame changing, then
-                    // notify the listeners and optionally animate it.
-                    if (w.hasMoved()) {
-                        // Frame has moved, containing content frame has also moved, and we're not
-                        // currently animating... let's do something.
-                        final int left = w.mFrame.left;
-                        final int top = w.mFrame.top;
-                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0) {
-                            Animation a = AnimationUtils.loadAnimation(mContext,
-                                    com.android.internal.R.anim.window_move_from_decor);
-                            winAnimator.setAnimation(a);
-                            winAnimator.mAnimDw = w.mLastFrame.left - left;
-                            winAnimator.mAnimDh = w.mLastFrame.top - top;
-                            winAnimator.mAnimateMove = true;
-                            winAnimator.mAnimatingMove = true;
-                        }
-
-                        //TODO (multidisplay): Accessibility supported only for the default display.
-                        if (mAccessibilityController != null
-                                && displayId == Display.DEFAULT_DISPLAY) {
-                            mAccessibilityController.onSomeWindowResizedOrMovedLocked();
-                        }
-
-                        try {
-                            w.mClient.moved(left, top);
-                        } catch (RemoteException e) {
-                        }
-                    }
-
-                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
-                    w.mContentChanged = false;
-
-                    // Moved from updateWindowsAndWallpaperLocked().
-                    if (w.mHasSurface) {
-                        // Take care of the window being ready to display.
-                        final boolean committed =
-                                winAnimator.commitFinishDrawingLocked();
-                        if (isDefaultDisplay && committed) {
-                            if (w.mAttrs.type == TYPE_DREAM) {
-                                // HACK: When a dream is shown, it may at that
-                                // point hide the lock screen.  So we need to
-                                // redo the layout to let the phone window manager
-                                // make this happen.
-                                displayContent.pendingLayoutChanges |=
-                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-                                if (DEBUG_LAYOUT_REPEATS) {
-                                    debugLayoutRepeats(
-                                            "dream and commitFinishDrawingLocked true",
-                                            displayContent.pendingLayoutChanges);
-                                }
-                            }
-                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
-                                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                                            "First draw done in potential wallpaper target " + w);
-                                mInnerFields.mWallpaperMayChange = true;
-                                displayContent.pendingLayoutChanges |=
-                                        WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-                                if (DEBUG_LAYOUT_REPEATS) {
-                                    debugLayoutRepeats(
-                                            "wallpaper and commitFinishDrawingLocked true",
-                                            displayContent.pendingLayoutChanges);
-                                }
-                            }
-                        }
-
-                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
-                    }
-
-                    final AppWindowToken atoken = w.mAppToken;
-                    if (DEBUG_STARTING_WINDOW && atoken != null
-                            && w == atoken.startingWindow) {
-                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
-                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
-                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
-                    }
-                    if (atoken != null
-                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
-                        if (atoken.lastTransactionSequence != mTransactionSequence) {
-                            atoken.lastTransactionSequence = mTransactionSequence;
-                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                            atoken.startingDisplayed = false;
-                        }
-                        if ((w.isOnScreenIgnoringKeyguard()
-                                || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
-                                && !w.mExiting && !w.mDestroying) {
-                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
-                                        + ", isAnimating=" + winAnimator.isAnimating());
-                                if (!w.isDrawnLw()) {
-                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
-                                            + " pv=" + w.mPolicyVisibility
-                                            + " mDrawState=" + winAnimator.drawStateToString()
-                                            + " ah=" + w.mAttachedHidden
-                                            + " th=" + atoken.hiddenRequested
-                                            + " a=" + winAnimator.mAnimating);
-                                }
-                            }
-                            if (w != atoken.startingWindow) {
-                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
-                                    atoken.numInterestingWindows++;
-                                    if (w.isDrawnLw()) {
-                                        atoken.numDrawnWindows++;
-                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                                "tokenMayBeDrawn: " + atoken
-                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
-                                                + " mAppFreezing=" + w.mAppFreezing);
-                                        updateAllDrawn = true;
-                                    }
-                                }
-                            } else if (w.isDrawnLw()) {
-                                atoken.startingDisplayed = true;
-                            }
-                        }
-                    }
-
-                    if (isDefaultDisplay && someoneLosingFocus && (w == mCurrentFocus)
-                            && w.isDisplayedLw()) {
-                        focusDisplayed = true;
-                    }
-
-                    updateResizingWindows(w);
-                }
-
-                mDisplayManagerInternal.setDisplayProperties(displayId,
-                        mInnerFields.mDisplayHasContent, mInnerFields.mPreferredRefreshRate,
-                        mInnerFields.mPreferredModeId,
-                        true /* inTraversal, must call performTraversalInTrans... below */);
-
-                getDisplayContentLocked(displayId).stopDimmingIfNeeded();
-
-                if (updateAllDrawn) {
-                    updateAllDrawnLocked(displayContent);
-                }
-            }
-
-            if (focusDisplayed) {
-                mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS);
-            }
-
-            // Give the display manager a chance to adjust properties
-            // like display rotation if it needs to.
-            mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
-
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
-                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
-        }
-
-        final WindowList defaultWindows = defaultDisplay.getWindowList();
-
-        // If we are ready to perform an app transition, check through
-        // all of the app tokens to be shown and see if they are ready
-        // to go.
-        if (mAppTransition.isReady()) {
-            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        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
-            // reflects the correct Z-order, but the window list may now
-            // be out of sync with it.  So here we will just rebuild the
-            // entire app window list.  Fun!
-            defaultDisplay.pendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked();
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock",
-                defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mInnerFields.mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
-                && !mAppTransition.isReady()) {
-            // At this point, there was a window with a wallpaper that
-            // was force hiding other windows behind it, but now it
-            // is going away.  This may be simple -- just animate
-            // away the wallpaper and its window -- or it may be
-            // hard -- the wallpaper now needs to be shown behind
-            // something that was hidden.
-            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked",
-                defaultDisplay.pendingLayoutChanges);
-        }
-        mInnerFields.mWallpaperForceHidingChanged = false;
-
-        if (mInnerFields.mWallpaperMayChange) {
-            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "Wallpaper may change!  Adjusting");
-            defaultDisplay.pendingLayoutChanges |=
-                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        if (mFocusMayChange) {
-            mFocusMayChange = false;
-            if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
-                    false /*updateInputWindows*/)) {
-                updateInputWindowsNeeded = true;
-                defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
-            }
-        }
-
-        if (needsLayout()) {
-            defaultDisplay.pendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
-            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
-                    defaultDisplay.pendingLayoutChanges);
-        }
-
-        for (i = mResizingWindows.size() - 1; i >= 0; i--) {
-            WindowState win = mResizingWindows.get(i);
-            if (win.mAppFreezing) {
-                // Don't remove this window until rotation has completed.
-                continue;
-            }
-            win.reportResized();
-            mResizingWindows.remove(i);
-        }
-
-        if (DEBUG_ORIENTATION && mDisplayFrozen) Slog.v(TAG,
-                "With display frozen, orientationChangeComplete="
-                + mInnerFields.mOrientationChangeComplete);
-        if (mInnerFields.mOrientationChangeComplete) {
-            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
-                mLastFinishedFreezeSource = mInnerFields.mLastWindowFreezeSource;
-                mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
-            }
-            stopFreezingDisplayLocked();
-        }
-
-        // Destroy the surface of any windows that are no longer visible.
-        boolean wallpaperDestroyed = false;
-        i = mDestroySurface.size();
-        if (i > 0) {
-            do {
-                i--;
-                WindowState win = mDestroySurface.get(i);
-                win.mDestroying = false;
-                if (mInputMethodWindow == win) {
-                    mInputMethodWindow = null;
-                }
-                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
-                    wallpaperDestroyed = true;
-                }
-                win.mWinAnimator.destroySurfaceLocked();
-            } while (i > 0);
-            mDestroySurface.clear();
-        }
-
-        // Time to remove any exiting tokens?
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
-            for (i = exitingTokens.size() - 1; i >= 0; i--) {
-                WindowToken token = exitingTokens.get(i);
-                if (!token.hasVisible) {
-                    exitingTokens.remove(i);
-                    if (token.windowType == TYPE_WALLPAPER) {
-                        mWallpaperControllerLocked.removeWallpaperToken(token);
-                    }
-                }
-            }
-        }
-
-        // Time to remove any exiting applications?
-        for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
-            // Initialize state of exiting applications.
-            final AppTokenList exitingAppTokens =
-                    mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
-            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
-                AppWindowToken token = exitingAppTokens.get(i);
-                if (!token.hasVisible && !mClosingApps.contains(token) &&
-                        (!token.mIsExiting || token.allAppWindows.isEmpty())) {
-                    // Make sure there is no animation running on this token,
-                    // so any windows associated with it will be removed as
-                    // soon as their animations are complete
-                    token.mAppAnimator.clearAnimation();
-                    token.mAppAnimator.animating = false;
-                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG,
-                            "performLayout: App token exiting now removed" + token);
-                    token.removeAppFromTaskLocked();
-                }
-            }
-        }
-
-        if (wallpaperDestroyed) {
-            defaultDisplay.pendingLayoutChanges |=
-                    WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-            defaultDisplay.layoutNeeded = true;
-        }
-
-        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
-            if (displayContent.pendingLayoutChanges != 0) {
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Finally update all input windows now that the window changes have stabilized.
-        mInputMonitor.updateInputWindowsLw(true /*force*/);
-
-        setHoldScreenLocked(mInnerFields.mHoldScreen);
-        if (!mDisplayFrozen) {
-            if (mInnerFields.mScreenBrightness < 0 || mInnerFields.mScreenBrightness > 1.0f) {
-                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mInnerFields.mScreenBrightness));
-            }
-            if (mInnerFields.mButtonBrightness < 0 || mInnerFields.mButtonBrightness > 1.0f) {
-                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
-            } else {
-                mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
-                        toBrightnessOverride(mInnerFields.mButtonBrightness));
-            }
-            mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
-                    mInnerFields.mUserActivityTimeout);
-        }
-
-        if (mTurnOnScreen) {
-            if (mAllowTheaterModeWakeFromLayout
-                    || Settings.Global.getInt(mContext.getContentResolver(),
-                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
-                if (DEBUG_VISIBILITY || DEBUG_POWER) {
-                    Slog.v(TAG, "Turning screen on after layout!");
-                }
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.wm:TURN_ON");
-            }
-            mTurnOnScreen = false;
-        }
-
-        if (mInnerFields.mUpdateRotation) {
-            if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
-            if (updateRotationUncheckedLocked(false)) {
-                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-            } else {
-                mInnerFields.mUpdateRotation = false;
-            }
-        }
-
-        if (mWaitingForDrawnCallback != null ||
-                (mInnerFields.mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
-                        !mInnerFields.mUpdateRotation)) {
-            checkDrawnWindowsLocked();
-        }
-
-        final int N = mPendingRemove.size();
-        if (N > 0) {
-            if (mPendingRemoveTmp.length < N) {
-                mPendingRemoveTmp = new WindowState[N+10];
-            }
-            mPendingRemove.toArray(mPendingRemoveTmp);
-            mPendingRemove.clear();
-            DisplayContentList displayList = new DisplayContentList();
-            for (i = 0; i < N; i++) {
-                WindowState w = mPendingRemoveTmp[i];
-                removeWindowInnerLocked(w);
-                final DisplayContent displayContent = w.getDisplayContent();
-                if (displayContent != null && !displayList.contains(displayContent)) {
-                    displayList.add(displayContent);
-                }
-            }
-
-            for (DisplayContent displayContent : displayList) {
-                assignLayersLocked(displayContent.getWindowList());
-                displayContent.layoutNeeded = true;
-            }
-        }
-
-        // Remove all deferred displays stacks, tasks, and activities.
-        for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
-            mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
-        }
-
-        if (updateInputWindowsNeeded) {
-            mInputMonitor.updateInputWindowsLw(false /*force*/);
-        }
-        setFocusTaskRegion();
-
-        // Check to see if we are now in a state where the screen should
-        // be enabled, because the window obscured flags have changed.
-        enableScreenIfNeededLocked();
-
-        scheduleAnimationLocked();
-
-        if (DEBUG_WINDOW_TRACE) {
-            Slog.e(TAG, "performLayoutAndPlaceSurfacesLockedInner exit: animating="
-                    + mAnimator.mAnimating);
-        }
-    }
-
-    private int toBrightnessOverride(float value) {
-        return (int)(value * PowerManager.BRIGHTNESS_ON);
-    }
-
     void checkDrawnWindowsLocked() {
         if (mWaitingForDrawn.isEmpty() || mWaitingForDrawnCallback == null) {
             return;
@@ -9826,7 +8434,7 @@
         }
     }
 
-    private boolean needsLayout() {
+    boolean needsLayout() {
         final int numDisplays = mDisplayContents.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             final DisplayContent displayContent = mDisplayContents.valueAt(displayNdx);
@@ -9837,41 +8445,6 @@
         return false;
     }
 
-    boolean copyAnimToLayoutParamsLocked() {
-        boolean doRequest = false;
-
-        final int bulkUpdateParams = mAnimator.mBulkUpdateParams;
-        if ((bulkUpdateParams & LayoutFields.SET_UPDATE_ROTATION) != 0) {
-            mInnerFields.mUpdateRotation = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_MAY_CHANGE) != 0) {
-            mInnerFields.mWallpaperMayChange = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_FORCE_HIDING_CHANGED) != 0) {
-            mInnerFields.mWallpaperForceHidingChanged = true;
-            doRequest = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
-            mInnerFields.mOrientationChangeComplete = false;
-        } else {
-            mInnerFields.mOrientationChangeComplete = true;
-            mInnerFields.mLastWindowFreezeSource = mAnimator.mLastWindowFreezeSource;
-            if (mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
-                doRequest = true;
-            }
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_TURN_ON_SCREEN) != 0) {
-            mTurnOnScreen = true;
-        }
-        if ((bulkUpdateParams & LayoutFields.SET_WALLPAPER_ACTION_PENDING) != 0) {
-            mInnerFields.mWallpaperActionPending = true;
-        }
-
-        return doRequest;
-    }
-
     /** If a window that has an animation specifying a colored background and the current wallpaper
      * is visible, then the color goes *below* the wallpaper so we don't cause the wallpaper to
      * suddenly disappear. */
@@ -9995,7 +8568,7 @@
         return leakedSurface || killedApps;
     }
 
-    private boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
+    boolean updateFocusedWindowLocked(int mode, boolean updateInputWindows) {
         WindowState newFocus = computeFocusedWindowLocked();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
@@ -10024,7 +8597,8 @@
             if (imWindowChanged && oldFocus != mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
-                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
+                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
+                            updateInputWindows);
                     focusChanged &= ~WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                 } else if (mode == UPDATE_FOCUS_WILL_PLACE_SURFACES) {
                     // Client will do the layout, but we need to assign layers
@@ -10037,7 +8611,8 @@
                 // The change in focus caused us to need to do a layout.  Okay.
                 displayContent.layoutNeeded = true;
                 if (mode == UPDATE_FOCUS_PLACING_SURFACES) {
-                    performLayoutLockedInner(displayContent, true /*initial*/, updateInputWindows);
+                    mWindowPlacerLocked.performLayoutLockedInner(displayContent, true /*initial*/,
+                            updateInputWindows);
                 }
             }
 
@@ -10065,7 +8640,7 @@
         return null;
     }
 
-    private WindowState findFocusedWindowLocked(DisplayContent displayContent) {
+    WindowState findFocusedWindowLocked(DisplayContent displayContent) {
         final WindowList windows = displayContent.getWindowList();
         for (int i = windows.size() - 1; i >= 0; i--) {
             final WindowState win = windows.get(i);
@@ -10189,7 +8764,7 @@
         }
     }
 
-    private void stopFreezingDisplayLocked() {
+    void stopFreezingDisplayLocked() {
         if (!mDisplayFrozen) {
             return;
         }
@@ -10396,7 +8971,7 @@
         synchronized (mWindowMap) {
             int visibility = mPolicy.adjustSystemUiVisibilityLw(mLastStatusBarVisibility);
             updateStatusBarVisibilityLocked(visibility);
-            performLayoutAndPlaceSurfacesLocked();
+            mWindowPlacerLocked.performSurfacePlacement();
         }
     }
 
@@ -11010,13 +9585,6 @@
         synchronized (mWindowMap) { }
     }
 
-    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
-        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
-            Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
-                    Integer.toHexString(pendingLayoutChanges));
-        }
-    }
-
     private DisplayContent newDisplayContentLocked(final Display display) {
         DisplayContent displayContent = new DisplayContent(display, this);
         final int displayId = display.getDisplayId();
@@ -11155,6 +9723,17 @@
         return mWindowMap;
     }
 
+    public void setReplacingWindow(IBinder token) {
+        synchronized (mWindowMap) {
+            AppWindowToken appWindowToken = findAppWindowToken(token);
+            if (appWindowToken == null) {
+                Slog.w(TAG, "Attempted to set replacing window on non-existing app token " + token);
+                return;
+            }
+            appWindowToken.mReplacingWindow = true;
+        }
+    }
+
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 761e5eb..49d260e 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -1255,6 +1256,33 @@
         mInputWindowHandle.inputChannel = null;
     }
 
+    void handleFlagDimBehind() {
+        if ((mAttrs.flags & FLAG_DIM_BEHIND) != 0 && isDisplayedLw() && !mExiting) {
+            final Task task = getTask();
+            if (task == null) {
+                return;
+            }
+            task.setContinueDimming();
+            if (!task.isDimming(mWinAnimator)) {
+                if (WindowManagerService.localLOGV) Slog.v(TAG, "Win " + this + " start dimming.");
+                task.startDimmingIfNeeded(mWinAnimator);
+            }
+        }
+    }
+
+    void maybeRemoveReplacedWindow() {
+        AppWindowToken token = mAppToken;
+        if (token != null && token.mReplacingWindow) {
+            token.mReplacingWindow = false;
+            for (int i = token.allAppWindows.size() - 1; i >= 0; i--) {
+                WindowState win = token.allAppWindows.get(i);
+                if (win.mExiting) {
+                    mService.removeWindowInnerLocked(win);
+                }
+            }
+        }
+    }
+
     private class DeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 109e627..efad8bf 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -27,8 +27,8 @@
 import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
 import static com.android.server.wm.WindowManagerService.SHOW_SURFACE_ALLOC;
 import static com.android.server.wm.WindowManagerService.localLOGV;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_ORIENTATION_CHANGE_COMPLETE;
-import static com.android.server.wm.WindowManagerService.LayoutFields.SET_TURN_ON_SCREEN;
+import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
+import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
 
 import android.content.Context;
 import android.graphics.Matrix;
@@ -424,8 +424,9 @@
         finishExit();
         final int displayId = mWin.getDisplayId();
         mAnimator.setPendingLayoutChanges(displayId, WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
-        if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats(
-                "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
+        if (WindowManagerService.DEBUG_LAYOUT_REPEATS)
+            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                    "WindowStateAnimator", mAnimator.getPendingLayoutChanges(displayId));
 
         if (mWin.mAppToken != null) {
             mWin.mAppToken.updateReportedVisibilityLocked();
@@ -1184,7 +1185,7 @@
                     + " screen=" + (screenAnimation ?
                             screenRotationAnimation.getEnterTransformation().getAlpha() : "null"));
             return;
-        } else if (mIsWallpaper && mService.mInnerFields.mWallpaperActionPending) {
+        } else if (mIsWallpaper && mService.mWindowPlacerLocked.mWallpaperActionPending) {
             return;
         }
 
@@ -1764,6 +1765,8 @@
                 mWin.mAppToken.updateReportedVisibilityLocked();
             }
 
+            mWin.maybeRemoveReplacedWindow();
+
             return true;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
new file mode 100644
index 0000000..ce07a9d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -0,0 +1,1523 @@
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.WindowManagerService.DEBUG;
+import static com.android.server.wm.WindowManagerService.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerService.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerService.DEBUG_LAYOUT_REPEATS;
+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_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerService.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerService.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerService.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerService.H.*;
+import static com.android.server.wm.WindowManagerService.LAYOUT_REPEAT_THRESHOLD;
+import static com.android.server.wm.WindowManagerService.MAX_ANIMATION_DURATION;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerService.TAG;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_PLACING_SURFACES;
+import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_WILL_PLACE_SURFACES;
+import static com.android.server.wm.WindowManagerService.WINDOWS_FREEZING_SCREENS_NONE;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.Debug;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+import android.view.Display;
+import android.view.DisplayInfo;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import java.util.ArrayList;
+
+/**
+ * Positions windows and their surfaces.
+ *
+ * It sets positions of windows by calculating their frames and then applies this by positioning
+ * surfaces according to these frames. Z layer is still assigned withing WindowManagerService.
+ */
+class WindowSurfacePlacer {
+    private final WindowManagerService mService;
+    private final WallpaperController mWallpaperControllerLocked;
+
+    private boolean mInLayout = false;
+
+    /** Only do a maximum of 6 repeated layouts. After that quit */
+    private int mLayoutRepeatCount;
+
+    static final int SET_UPDATE_ROTATION                = 1 << 0;
+    static final int SET_WALLPAPER_MAY_CHANGE           = 1 << 1;
+    static final int SET_FORCE_HIDING_CHANGED           = 1 << 2;
+    static final int SET_ORIENTATION_CHANGE_COMPLETE    = 1 << 3;
+    static final int SET_TURN_ON_SCREEN                 = 1 << 4;
+    static final int SET_WALLPAPER_ACTION_PENDING       = 1 << 5;
+
+    boolean mWallpaperMayChange = false;
+    boolean mOrientationChangeComplete = true;
+    boolean mWallpaperActionPending = false;
+
+    private boolean mWallpaperForceHidingChanged = false;
+    private Object mLastWindowFreezeSource = null;
+    private Session mHoldScreen = null;
+    private boolean mObscured = false;
+    private boolean mSyswin = false;
+    private float mScreenBrightness = -1;
+    private float mButtonBrightness = -1;
+    private long mUserActivityTimeout = -1;
+    private boolean mUpdateRotation = false;
+    private final Rect mTmpStartRect = new Rect();
+
+    // Set to true when the display contains content to show the user.
+    // When false, the display manager may choose to mirror or blank the display.
+    private boolean mDisplayHasContent = false;
+
+    // Only set while traversing the default display based on its content.
+    // Affects the behavior of mirroring on secondary displays.
+    private boolean mObscureApplicationContentOnSecondaryDisplays = false;
+
+    private float mPreferredRefreshRate = 0;
+
+    private int mPreferredModeId = 0;
+
+    public WindowSurfacePlacer(WindowManagerService service) {
+        mService = service;
+        mWallpaperControllerLocked = mService.mWallpaperControllerLocked;
+    }
+
+    final void performSurfacePlacement() {
+        int loopCount = 6;
+        do {
+            mService.mTraversalScheduled = false;
+            performSurfacePlacementLoop();
+            mService.mH.removeMessages(DO_TRAVERSAL);
+            loopCount--;
+        } while (mService.mTraversalScheduled && loopCount > 0);
+        mWallpaperActionPending = false;
+    }
+
+    private void performSurfacePlacementLoop() {
+        if (mInLayout) {
+            if (DEBUG) {
+                throw new RuntimeException("Recursive call!");
+            }
+            Slog.w(TAG,
+                    "performLayoutAndPlaceSurfacesLocked called while in layout. Callers="
+                    + Debug.getCallers(3));
+            return;
+        }
+
+        if (mService.mWaitingForConfig) {
+            // Our configuration has changed (most likely rotation), but we
+            // don't yet have the complete configuration to report to
+            // applications.  Don't do any window layout until we have it.
+            return;
+        }
+
+        if (!mService.mDisplayReady) {
+            // Not yet initialized, nothing to do.
+            return;
+        }
+
+        Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
+        mInLayout = true;
+
+        boolean recoveringMemory = false;
+        if (!mService.mForceRemoves.isEmpty()) {
+            recoveringMemory = true;
+            // Wait a little bit for things to settle down, and off we go.
+            while (!mService.mForceRemoves.isEmpty()) {
+                WindowState ws = mService.mForceRemoves.remove(0);
+                Slog.i(TAG, "Force removing: " + ws);
+                mService.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) {
+                }
+            }
+        }
+
+        try {
+            performSurfacePlacementInner(recoveringMemory);
+
+            mInLayout = false;
+
+            if (mService.needsLayout()) {
+                if (++mLayoutRepeatCount < 6) {
+                    mService.requestTraversalLocked();
+                } else {
+                    Slog.e(TAG, "Performed 6 layouts in a row. Skipping");
+                    mLayoutRepeatCount = 0;
+                }
+            } else {
+                mLayoutRepeatCount = 0;
+            }
+
+            if (mService.mWindowsChanged && !mService.mWindowChangeListeners.isEmpty()) {
+                mService.mH.removeMessages(REPORT_WINDOWS_CHANGE);
+                mService.mH.sendEmptyMessage(REPORT_WINDOWS_CHANGE);
+            }
+        } catch (RuntimeException e) {
+            mInLayout = false;
+            Slog.wtf(TAG, "Unhandled exception while laying out windows", e);
+        }
+
+        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+    }
+
+    void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
+        if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
+            Slog.v(TAG, "Layouts looping: " + msg +
+                    ", mPendingLayoutChanges = 0x" + Integer.toHexString(pendingLayoutChanges));
+        }
+    }
+
+    // "Something has changed!  Let's make it correct now."
+    private void performSurfacePlacementInner(boolean recoveringMemory) {
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.v(TAG,
+                    "performSurfacePlacementInner: entry. Called by "
+                    + Debug.getCallers(3));
+        }
+
+        int i;
+        boolean updateInputWindowsNeeded = false;
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            updateInputWindowsNeeded = mService.updateFocusedWindowLocked(
+                    UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
+        }
+
+        // Initialize state of exiting tokens.
+        final int numDisplays = mService.mDisplayContents.size();
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            for (i=displayContent.mExitingTokens.size()-1; i>=0; i--) {
+                displayContent.mExitingTokens.get(i).hasVisible = false;
+            }
+        }
+
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (int tokenNdx = exitingAppTokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                exitingAppTokens.get(tokenNdx).hasVisible = false;
+            }
+        }
+
+        mHoldScreen = null;
+        mScreenBrightness = -1;
+        mButtonBrightness = -1;
+        mUserActivityTimeout = -1;
+        mObscureApplicationContentOnSecondaryDisplays = false;
+
+        mService.mTransactionSequence++;
+
+        final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
+        final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
+        final int defaultDw = defaultInfo.logicalWidth;
+        final int defaultDh = defaultInfo.logicalHeight;
+
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                ">>> OPEN TRANSACTION performLayoutAndPlaceSurfaces");
+        SurfaceControl.openTransaction();
+        try {
+
+            if (mService.mWatermark != null) {
+                mService.mWatermark.positionSurface(defaultDw, defaultDh);
+            }
+            if (mService.mStrictModeFlash != null) {
+                mService.mStrictModeFlash.positionSurface(defaultDw, defaultDh);
+            }
+            if (mService.mCircularDisplayMask != null) {
+                mService.mCircularDisplayMask.positionSurface(defaultDw, defaultDh,
+                        mService.mRotation);
+            }
+            if (mService.mEmulatorDisplayOverlay != null) {
+                mService.mEmulatorDisplayOverlay.positionSurface(defaultDw, defaultDh,
+                        mService.mRotation);
+            }
+
+            boolean focusDisplayed = false;
+
+            for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+                final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+                boolean updateAllDrawn = false;
+                WindowList windows = displayContent.getWindowList();
+                DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                final int displayId = displayContent.getDisplayId();
+                final int dw = displayInfo.logicalWidth;
+                final int dh = displayInfo.logicalHeight;
+                final int innerDw = displayInfo.appWidth;
+                final int innerDh = displayInfo.appHeight;
+                final boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+
+                // Reset for each display.
+                mDisplayHasContent = false;
+                mPreferredRefreshRate = 0;
+                mPreferredModeId = 0;
+
+                int repeats = 0;
+                do {
+                    repeats++;
+                    if (repeats > 6) {
+                        Slog.w(TAG, "Animation repeat aborted after too many iterations");
+                        displayContent.layoutNeeded = false;
+                        break;
+                    }
+
+                    if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
+                            "On entry to LockedInner", displayContent.pendingLayoutChanges);
+
+                    if ((displayContent.pendingLayoutChanges &
+                            FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
+                            mWallpaperControllerLocked.adjustWallpaperWindows()) {
+                        mService.assignLayersLocked(windows);
+                        displayContent.layoutNeeded = true;
+                    }
+
+                    if (isDefaultDisplay && (displayContent.pendingLayoutChanges
+                            & FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG,
+                                "Computing new config from layout");
+                        if (mService.updateOrientationFromAppTokensLocked(true)) {
+                            displayContent.layoutNeeded = true;
+                            mService.mH.sendEmptyMessage(
+                                    SEND_NEW_CONFIGURATION);
+                        }
+                    }
+
+                    if ((displayContent.pendingLayoutChanges
+                            & FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                        displayContent.layoutNeeded = true;
+                    }
+
+                    // FIRST LOOP: Perform a layout, if needed.
+                    if (repeats < LAYOUT_REPEAT_THRESHOLD) {
+                        performLayoutLockedInner(displayContent, repeats == 1,
+                                false /*updateInputWindows*/);
+                    } else {
+                        Slog.w(TAG, "Layout repeat skipped after too many iterations");
+                    }
+
+                    // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think
+                    // it is animating.
+                    displayContent.pendingLayoutChanges = 0;
+
+                    if (isDefaultDisplay) {
+                        mService.mPolicy.beginPostLayoutPolicyLw(dw, dh);
+                        for (i = windows.size() - 1; i >= 0; i--) {
+                            WindowState w = windows.get(i);
+                            if (w.mHasSurface) {
+                                mService.mPolicy.applyPostLayoutPolicyLw(w, w.mAttrs,
+                                        w.mAttachedWindow);
+                            }
+                        }
+                        displayContent.pendingLayoutChanges |=
+                                mService.mPolicy.finishPostLayoutPolicyLw();
+                        if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats(
+                                "after finishPostLayoutPolicyLw",
+                                displayContent.pendingLayoutChanges);
+                    }
+                } while (displayContent.pendingLayoutChanges != 0);
+
+                mObscured = false;
+                mSyswin = false;
+                displayContent.resetDimming();
+
+                // Only used if default window
+                final boolean someoneLosingFocus = !mService.mLosingFocus.isEmpty();
+
+                final int N = windows.size();
+                for (i=N-1; i>=0; i--) {
+                    WindowState w = windows.get(i);
+                    final Task task = w.getTask();
+                    if (task == null && w.getAttrs().type != TYPE_PRIVATE_PRESENTATION) {
+                        continue;
+                    }
+
+                    final boolean obscuredChanged = w.mObscured != mObscured;
+
+                    // Update effect.
+                    w.mObscured = mObscured;
+                    if (!mObscured) {
+                        handleNotObscuredLocked(w, innerDw, innerDh);
+                    }
+
+                    if (task != null && !task.getContinueDimming()) {
+                        w.handleFlagDimBehind();
+                    }
+
+                    if (isDefaultDisplay && obscuredChanged
+                            && mWallpaperControllerLocked.isWallpaperTarget(w)
+                            && w.isVisibleLw()) {
+                        // This is the wallpaper target and its obscured state
+                        // changed... make sure the current wallaper's visibility
+                        // has been updated accordingly.
+                        mWallpaperControllerLocked.updateWallpaperVisibility();
+                    }
+
+                    final WindowStateAnimator winAnimator = w.mWinAnimator;
+
+                    // If the window has moved due to its containing content frame changing, then
+                    // notify the listeners and optionally animate it.
+                    if (w.hasMoved()) {
+                        // Frame has moved, containing content frame has also moved, and we're not
+                        // currently animating... let's do something.
+                        final int left = w.mFrame.left;
+                        final int top = w.mFrame.top;
+                        if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0) {
+                            Animation a = AnimationUtils.loadAnimation(mService.mContext,
+                                    com.android.internal.R.anim.window_move_from_decor);
+                            winAnimator.setAnimation(a);
+                            winAnimator.mAnimDw = w.mLastFrame.left - left;
+                            winAnimator.mAnimDh = w.mLastFrame.top - top;
+                            winAnimator.mAnimateMove = true;
+                            winAnimator.mAnimatingMove = true;
+                        }
+
+                        //TODO (multidisplay): Accessibility supported only for the default display.
+                        if (mService.mAccessibilityController != null
+                                && displayId == Display.DEFAULT_DISPLAY) {
+                            mService.mAccessibilityController.onSomeWindowResizedOrMovedLocked();
+                        }
+
+                        try {
+                            w.mClient.moved(left, top);
+                        } catch (RemoteException e) {
+                        }
+                    }
+
+                    //Slog.i(TAG, "Window " + this + " clearing mContentChanged - done placing");
+                    w.mContentChanged = false;
+
+                    // Moved from updateWindowsAndWallpaperLocked().
+                    if (w.mHasSurface) {
+                        // Take care of the window being ready to display.
+                        final boolean committed =
+                                winAnimator.commitFinishDrawingLocked();
+                        if (isDefaultDisplay && committed) {
+                            if (w.mAttrs.type == TYPE_DREAM) {
+                                // HACK: When a dream is shown, it may at that
+                                // point hide the lock screen.  So we need to
+                                // redo the layout to let the phone window manager
+                                // make this happen.
+                                displayContent.pendingLayoutChanges |=
+                                        FINISH_LAYOUT_REDO_LAYOUT;
+                                if (DEBUG_LAYOUT_REPEATS) {
+                                    debugLayoutRepeats(
+                                            "dream and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
+                                }
+                            }
+                            if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
+                                if (DEBUG_WALLPAPER_LIGHT)
+                                    Slog.v(TAG,
+                                            "First draw done in potential wallpaper target " + w);
+                                mWallpaperMayChange = true;
+                                displayContent.pendingLayoutChanges |=
+                                        FINISH_LAYOUT_REDO_WALLPAPER;
+                                if (DEBUG_LAYOUT_REPEATS) {
+                                    debugLayoutRepeats(
+                                            "wallpaper and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
+                                }
+                            }
+                        }
+
+                        winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
+                    }
+
+                    final AppWindowToken atoken = w.mAppToken;
+                    if (DEBUG_STARTING_WINDOW && atoken != null
+                            && w == atoken.startingWindow) {
+                        Slog.d(TAG, "updateWindows: starting " + w
+                                + " isOnScreen=" + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
+                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                    }
+                    if (atoken != null
+                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
+                        if (atoken.lastTransactionSequence != mService.mTransactionSequence) {
+                            atoken.lastTransactionSequence = mService.mTransactionSequence;
+                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                            atoken.startingDisplayed = false;
+                        }
+                        if ((w.isOnScreenIgnoringKeyguard()
+                                || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
+                                && !w.mExiting && !w.mDestroying) {
+                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+                                Slog.v(TAG, "Eval win " + w + ": isDrawn="
+                                        + w.isDrawnLw()
+                                        + ", isAnimating=" + winAnimator.isAnimating());
+                                if (!w.isDrawnLw()) {
+                                    Slog.v(TAG, "Not displayed: s="
+                                            + winAnimator.mSurfaceControl
+                                            + " pv=" + w.mPolicyVisibility
+                                            + " mDrawState=" + winAnimator.drawStateToString()
+                                            + " ah=" + w.mAttachedHidden
+                                            + " th=" + atoken.hiddenRequested
+                                            + " a=" + winAnimator.mAnimating);
+                                }
+                            }
+                            if (w != atoken.startingWindow) {
+                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+                                    atoken.numInterestingWindows++;
+                                    if (w.isDrawnLw()) {
+                                        atoken.numDrawnWindows++;
+                                        if (DEBUG_VISIBILITY
+                                                || DEBUG_ORIENTATION)
+                                            Slog.v(TAG,
+                                                "tokenMayBeDrawn: " + atoken
+                                                + " freezingScreen="
+                                                + atoken.mAppAnimator.freezingScreen
+                                                + " mAppFreezing=" + w.mAppFreezing);
+                                        updateAllDrawn = true;
+                                    }
+                                }
+                            } else if (w.isDrawnLw()) {
+                                atoken.startingDisplayed = true;
+                            }
+                        }
+                    }
+
+                    if (isDefaultDisplay && someoneLosingFocus && (w == mService.mCurrentFocus)
+                            && w.isDisplayedLw()) {
+                        focusDisplayed = true;
+                    }
+
+                    mService.updateResizingWindows(w);
+                }
+
+                mService.mDisplayManagerInternal.setDisplayProperties(displayId,
+                        mDisplayHasContent,
+                        mPreferredRefreshRate,
+                        mPreferredModeId,
+                        true /* inTraversal, must call performTraversalInTrans... below */);
+
+                mService.getDisplayContentLocked(displayId).stopDimmingIfNeeded();
+
+                if (updateAllDrawn) {
+                    updateAllDrawnLocked(displayContent);
+                }
+            }
+
+            if (focusDisplayed) {
+                mService.mH.sendEmptyMessage(REPORT_LOSING_FOCUS);
+            }
+
+            // Give the display manager a chance to adjust properties
+            // like display rotation if it needs to.
+            mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+
+        } catch (RuntimeException e) {
+            Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
+                    "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
+        }
+
+        final WindowList defaultWindows = defaultDisplay.getWindowList();
+
+        // If we are ready to perform an app transition, check through
+        // all of the app tokens to be shown and see if they are ready
+        // to go.
+        if (mService.mAppTransition.isReady()) {
+            defaultDisplay.pendingLayoutChanges |= handleAppTransitionReadyLocked(defaultWindows);
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after handleAppTransitionReadyLocked",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (!mService.mAnimator.mAppWindowAnimating && mService.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
+            // reflects the correct Z-order, but the window list may now
+            // be out of sync with it.  So here we will just rebuild the
+            // entire app window list.  Fun!
+            defaultDisplay.pendingLayoutChanges |=
+                    mService.handleAnimatingStoppedAndTransitionLocked();
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after handleAnimStopAndXitionLock",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mWallpaperForceHidingChanged && defaultDisplay.pendingLayoutChanges == 0
+                && !mService.mAppTransition.isReady()) {
+            // At this point, there was a window with a wallpaper that
+            // was force hiding other windows behind it, but now it
+            // is going away.  This may be simple -- just animate
+            // away the wallpaper and its window -- or it may be
+            // hard -- the wallpaper now needs to be shown behind
+            // something that was hidden.
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS)
+                debugLayoutRepeats("after animateAwayWallpaperLocked",
+                        defaultDisplay.pendingLayoutChanges);
+        }
+        mWallpaperForceHidingChanged = false;
+
+        if (mWallpaperMayChange) {
+            if (DEBUG_WALLPAPER_LIGHT)
+                Slog.v(TAG, "Wallpaper may change!  Adjusting");
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("WallpaperMayChange",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        if (mService.mFocusMayChange) {
+            mService.mFocusMayChange = false;
+            if (mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                    false /*updateInputWindows*/)) {
+                updateInputWindowsNeeded = true;
+                defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_ANIM;
+            }
+        }
+
+        if (mService.needsLayout()) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_LAYOUT;
+            if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded",
+                    defaultDisplay.pendingLayoutChanges);
+        }
+
+        for (i = mService.mResizingWindows.size() - 1; i >= 0; i--) {
+            WindowState win = mService.mResizingWindows.get(i);
+            if (win.mAppFreezing) {
+                // Don't remove this window until rotation has completed.
+                continue;
+            }
+            win.reportResized();
+            mService.mResizingWindows.remove(i);
+        }
+
+        if (DEBUG_ORIENTATION && mService.mDisplayFrozen)
+            Slog.v(TAG,
+                "With display frozen, orientationChangeComplete="
+                + mOrientationChangeComplete);
+        if (mOrientationChangeComplete) {
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_NONE;
+                mService.mLastFinishedFreezeSource = mLastWindowFreezeSource;
+                mService.mH.removeMessages(WINDOW_FREEZE_TIMEOUT);
+            }
+            mService.stopFreezingDisplayLocked();
+        }
+
+        // Destroy the surface of any windows that are no longer visible.
+        boolean wallpaperDestroyed = false;
+        i = mService.mDestroySurface.size();
+        if (i > 0) {
+            do {
+                i--;
+                WindowState win = mService.mDestroySurface.get(i);
+                win.mDestroying = false;
+                if (mService.mInputMethodWindow == win) {
+                    mService.mInputMethodWindow = null;
+                }
+                if (mWallpaperControllerLocked.isWallpaperTarget(win)) {
+                    wallpaperDestroyed = true;
+                }
+                win.mWinAnimator.destroySurfaceLocked();
+            } while (i > 0);
+            mService.mDestroySurface.clear();
+        }
+
+        // Time to remove any exiting tokens?
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            ArrayList<WindowToken> exitingTokens = displayContent.mExitingTokens;
+            for (i = exitingTokens.size() - 1; i >= 0; i--) {
+                WindowToken token = exitingTokens.get(i);
+                if (!token.hasVisible) {
+                    exitingTokens.remove(i);
+                    if (token.windowType == TYPE_WALLPAPER) {
+                        mWallpaperControllerLocked.removeWallpaperToken(token);
+                    }
+                }
+            }
+        }
+
+        // Time to remove any exiting applications?
+        for (int stackNdx = mService.mStackIdToStack.size() - 1; stackNdx >= 0; --stackNdx) {
+            // Initialize state of exiting applications.
+            final AppTokenList exitingAppTokens =
+                    mService.mStackIdToStack.valueAt(stackNdx).mExitingAppTokens;
+            for (i = exitingAppTokens.size() - 1; i >= 0; i--) {
+                AppWindowToken token = exitingAppTokens.get(i);
+                if (!token.hasVisible && !mService.mClosingApps.contains(token) &&
+                        (!token.mIsExiting || token.allAppWindows.isEmpty())) {
+                    // Make sure there is no animation running on this token,
+                    // so any windows associated with it will be removed as
+                    // soon as their animations are complete
+                    token.mAppAnimator.clearAnimation();
+                    token.mAppAnimator.animating = false;
+                    if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT)
+                        Slog.v(TAG,
+                                "performLayout: App token exiting now removed" + token);
+                    token.removeAppFromTaskLocked();
+                }
+            }
+        }
+
+        if (wallpaperDestroyed) {
+            defaultDisplay.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+            defaultDisplay.layoutNeeded = true;
+        }
+
+        for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            if (displayContent.pendingLayoutChanges != 0) {
+                displayContent.layoutNeeded = true;
+            }
+        }
+
+        // Finally update all input windows now that the window changes have stabilized.
+        mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+
+        mService.setHoldScreenLocked(mHoldScreen);
+        if (!mService.mDisplayFrozen) {
+            if (mScreenBrightness < 0 || mScreenBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mScreenBrightness));
+            }
+            if (mButtonBrightness < 0
+                    || mButtonBrightness > 1.0f) {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(-1);
+            } else {
+                mService.mPowerManagerInternal.setButtonBrightnessOverrideFromWindowManager(
+                        toBrightnessOverride(mButtonBrightness));
+            }
+            mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
+                    mUserActivityTimeout);
+        }
+
+        if (mService.mTurnOnScreen) {
+            if (mService.mAllowTheaterModeWakeFromLayout
+                    || Settings.Global.getInt(mService.mContext.getContentResolver(),
+                        Settings.Global.THEATER_MODE_ON, 0) == 0) {
+                if (DEBUG_VISIBILITY || DEBUG_POWER) {
+                    Slog.v(TAG, "Turning screen on after layout!");
+                }
+                mService.mPowerManager.wakeUp(SystemClock.uptimeMillis(),
+                        "android.server.wm:TURN_ON");
+            }
+            mService.mTurnOnScreen = false;
+        }
+
+        if (mUpdateRotation) {
+            if (DEBUG_ORIENTATION) Slog.d(TAG,
+                    "Performing post-rotate rotation");
+            if (mService.updateRotationUncheckedLocked(false)) {
+                mService.mH.sendEmptyMessage(SEND_NEW_CONFIGURATION);
+            } else {
+                mUpdateRotation = false;
+            }
+        }
+
+        if (mService.mWaitingForDrawnCallback != null ||
+                (mOrientationChangeComplete && !defaultDisplay.layoutNeeded &&
+                        !mUpdateRotation)) {
+            mService.checkDrawnWindowsLocked();
+        }
+
+        final int N = mService.mPendingRemove.size();
+        if (N > 0) {
+            if (mService.mPendingRemoveTmp.length < N) {
+                mService.mPendingRemoveTmp = new WindowState[N+10];
+            }
+            mService.mPendingRemove.toArray(mService.mPendingRemoveTmp);
+            mService.mPendingRemove.clear();
+            DisplayContentList displayList = new DisplayContentList();
+            for (i = 0; i < N; i++) {
+                WindowState w = mService.mPendingRemoveTmp[i];
+                mService.removeWindowInnerLocked(w);
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && !displayList.contains(displayContent)) {
+                    displayList.add(displayContent);
+                }
+            }
+
+            for (DisplayContent displayContent : displayList) {
+                mService.assignLayersLocked(displayContent.getWindowList());
+                displayContent.layoutNeeded = true;
+            }
+        }
+
+        // Remove all deferred displays stacks, tasks, and activities.
+        for (int displayNdx = mService.mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+            mService.mDisplayContents.valueAt(displayNdx).checkForDeferredActions();
+        }
+
+        if (updateInputWindowsNeeded) {
+            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
+        mService.setFocusTaskRegion();
+
+        // Check to see if we are now in a state where the screen should
+        // be enabled, because the window obscured flags have changed.
+        mService.enableScreenIfNeededLocked();
+
+        mService.scheduleAnimationLocked();
+
+        if (DEBUG_WINDOW_TRACE) {
+            Slog.e(TAG,
+                    "performSurfacePlacementInner exit: animating="
+                            + mService.mAnimator.mAnimating);
+        }
+    }
+
+    boolean isInLayout() {
+        return mInLayout;
+    }
+
+    final void performLayoutLockedInner(final DisplayContent displayContent,
+            boolean initial, boolean updateInputWindows) {
+        if (!displayContent.layoutNeeded) {
+            return;
+        }
+        displayContent.layoutNeeded = false;
+        WindowList windows = displayContent.getWindowList();
+        boolean isDefaultDisplay = displayContent.isDefaultDisplay;
+
+        DisplayInfo displayInfo = displayContent.getDisplayInfo();
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
+
+        if (mService.mInputConsumer != null) {
+            mService.mInputConsumer.layout(dw, dh);
+        }
+
+        final int N = windows.size();
+        int i;
+
+        if (DEBUG_LAYOUT) {
+            Slog.v(TAG, "-------------------------------------");
+            Slog.v(TAG, "performLayout: needed="
+                    + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh);
+        }
+
+        mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation);
+        if (isDefaultDisplay) {
+            // Not needed on non-default displays.
+            mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
+            mService.mScreenRect.set(0, 0, dw, dh);
+        }
+
+        mService.mPolicy.getContentRectLw(mService.mTmpContentRect);
+        displayContent.resize(mService.mTmpContentRect);
+
+        int seq = mService.mLayoutSeq+1;
+        if (seq < 0) seq = 0;
+        mService.mLayoutSeq = seq;
+
+        boolean behindDream = false;
+
+        // First perform layout of any root windows (not attached
+        // to another window).
+        int topAttached = -1;
+        for (i = N-1; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+
+            // Don't do layout of a window if it is not visible, or
+            // soon won't be visible, to avoid wasting time and funky
+            // changes while a window is animating away.
+            final boolean gone = (behindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs))
+                    || win.isGoneForLayoutLw();
+
+            if (DEBUG_LAYOUT && !win.mLayoutAttached) {
+                Slog.v(TAG, "1ST PASS " + win
+                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
+                        + " mLayoutAttached=" + win.mLayoutAttached
+                        + " screen changed=" + win.isConfigChanged());
+                final AppWindowToken atoken = win.mAppToken;
+                if (gone) Slog.v(TAG, "  GONE: mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled="
+                        + win.mRelayoutCalled + " hidden="
+                        + win.mRootToken.hidden + " hiddenRequested="
+                        + (atoken != null && atoken.hiddenRequested)
+                        + " mAttachedHidden=" + win.mAttachedHidden);
+                else Slog.v(TAG, "  VIS: mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled="
+                        + win.mRelayoutCalled + " hidden="
+                        + win.mRootToken.hidden + " hiddenRequested="
+                        + (atoken != null && atoken.hiddenRequested)
+                        + " mAttachedHidden=" + win.mAttachedHidden);
+            }
+
+            // If this view is GONE, then skip it -- keep the current
+            // frame, and let the caller know so they can ignore it
+            // if they want.  (We do the normal layout for INVISIBLE
+            // windows, since that means "perform layout as normal,
+            // just don't display").
+            if (!gone || !win.mHaveFrame || win.mLayoutNeeded
+                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+                            ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
+                            (win.mHasSurface && win.mAppToken != null &&
+                            win.mAppToken.layoutConfigChanges)))) {
+                if (!win.mLayoutAttached) {
+                    if (initial) {
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
+                        win.mContentChanged = false;
+                    }
+                    if (win.mAttrs.type == TYPE_DREAM) {
+                        // Don't layout windows behind a dream, so that if it
+                        // does stuff like hide the status bar we won't get a
+                        // bad transition when it goes away.
+                        behindDream = true;
+                    }
+                    win.mLayoutNeeded = false;
+                    win.prelayout();
+                    mService.mPolicy.layoutWindowLw(win, null);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
+                            "  LAYOUT: mFrame="
+                            + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame="
+                            + win.mDisplayFrame);
+                } else {
+                    if (topAttached < 0) topAttached = i;
+                }
+            }
+        }
+
+        boolean attachedBehindDream = false;
+
+        // Now perform layout of attached windows, which usually
+        // depend on the position of the window they are attached to.
+        // XXX does not deal with windows that are attached to windows
+        // that are themselves attached.
+        for (i = topAttached; i >= 0; i--) {
+            final WindowState win = windows.get(i);
+
+            if (win.mLayoutAttached) {
+                if (DEBUG_LAYOUT) Slog.v(TAG,
+                        "2ND PASS " + win + " mHaveFrame=" + win.mHaveFrame + " mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled=" + win.mRelayoutCalled);
+                // If this view is GONE, then skip it -- keep the current
+                // frame, and let the caller know so they can ignore it
+                // if they want.  (We do the normal layout for INVISIBLE
+                // windows, since that means "perform layout as normal,
+                // just don't display").
+                if (attachedBehindDream && mService.mPolicy.canBeForceHidden(win, win.mAttrs)) {
+                    continue;
+                }
+                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
+                        || !win.mHaveFrame || win.mLayoutNeeded) {
+                    if (initial) {
+                        //Slog.i(TAG, "Window " + this + " clearing mContentChanged - initial");
+                        win.mContentChanged = false;
+                    }
+                    win.mLayoutNeeded = false;
+                    win.prelayout();
+                    mService.mPolicy.layoutWindowLw(win, win.mAttachedWindow);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG,
+                            "  LAYOUT: mFrame=" + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame=" + win.mDisplayFrame);
+                }
+            } else if (win.mAttrs.type == TYPE_DREAM) {
+                // Don't layout windows behind a dream, so that if it
+                // does stuff like hide the status bar we won't get a
+                // bad transition when it goes away.
+                attachedBehindDream = behindDream;
+            }
+        }
+
+        // Window frames may have changed.  Tell the input dispatcher about it.
+        mService.mInputMonitor.setUpdateInputWindowsNeededLw();
+        if (updateInputWindows) {
+            mService.mInputMonitor.updateInputWindowsLw(false /*force*/);
+        }
+
+        mService.mPolicy.finishLayoutLw();
+    }
+
+    /**
+     * @param windows List of windows on default display.
+     * @return bitmap indicating if another pass through layout must be made.
+     */
+    private int handleAppTransitionReadyLocked(WindowList windows) {
+        int appsCount = mService.mOpeningApps.size();
+        if (!transitionGoodToGo(appsCount)) {
+            return 0;
+        }
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "**** GOOD TO GO");
+        int transit = mService.mAppTransition.getAppTransition();
+        if (mService.mSkipAppTransitionAnimation) {
+            transit = AppTransition.TRANSIT_UNSET;
+        }
+        mService.mSkipAppTransitionAnimation = false;
+        mService.mNoAnimationNotifyOnTransitionFinished.clear();
+
+        mService.mH.removeMessages(APP_TRANSITION_TIMEOUT);
+
+        mService.rebuildAppWindowListLocked();
+
+        mWallpaperMayChange = false;
+
+        // The top-most window will supply the layout params,
+        // and we will determine it below.
+        WindowManager.LayoutParams animLp = null;
+        int bestAnimLayer = -1;
+        boolean fullscreenAnim = false;
+        boolean voiceInteraction = false;
+
+        final WindowState lowerWallpaperTarget =
+                mWallpaperControllerLocked.getLowerWallpaperTarget();
+        final WindowState upperWallpaperTarget =
+                mWallpaperControllerLocked.getUpperWallpaperTarget();
+
+        boolean openingAppHasWallpaper = false;
+        boolean closingAppHasWallpaper = false;
+        final AppWindowToken lowerWallpaperAppToken;
+        final AppWindowToken upperWallpaperAppToken;
+        if (lowerWallpaperTarget == null) {
+            lowerWallpaperAppToken = upperWallpaperAppToken = null;
+        } else {
+            lowerWallpaperAppToken = lowerWallpaperTarget.mAppToken;
+            upperWallpaperAppToken = upperWallpaperTarget.mAppToken;
+        }
+
+        int i;
+        // Do a first pass through the tokens for two
+        // things:
+        // (1) Determine if both the closing and opening
+        // app token sets are wallpaper targets, in which
+        // case special animations are needed
+        // (since the wallpaper needs to stay static
+        // behind them).
+        // (2) Find the layout params of the top-most
+        // application window in the tokens, which is
+        // what will control the animation theme.
+        final int closingAppsCount = mService.mClosingApps.size();
+        appsCount = closingAppsCount + mService.mOpeningApps.size();
+        for (i = 0; i < appsCount; i++) {
+            final AppWindowToken wtoken;
+            if (i < closingAppsCount) {
+                wtoken = mService.mClosingApps.valueAt(i);
+                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+                    closingAppHasWallpaper = true;
+                }
+            } else {
+                wtoken = mService.mOpeningApps.valueAt(i - closingAppsCount);
+                if (wtoken == lowerWallpaperAppToken || wtoken == upperWallpaperAppToken) {
+                    openingAppHasWallpaper = true;
+                }
+            }
+
+            voiceInteraction |= wtoken.voiceInteraction;
+
+            if (wtoken.appFullscreen) {
+                WindowState ws = wtoken.findMainWindow();
+                if (ws != null) {
+                    animLp = ws.mAttrs;
+                    bestAnimLayer = ws.mLayer;
+                    fullscreenAnim = true;
+                }
+            } else if (!fullscreenAnim) {
+                WindowState ws = wtoken.findMainWindow();
+                if (ws != null) {
+                    if (ws.mLayer > bestAnimLayer) {
+                        animLp = ws.mAttrs;
+                        bestAnimLayer = ws.mLayer;
+                    }
+                }
+            }
+        }
+
+        transit = maybeUpdateTransitToWallpaper(transit, openingAppHasWallpaper,
+                closingAppHasWallpaper, lowerWallpaperTarget, upperWallpaperTarget);
+
+        // If all closing windows are obscured, then there is
+        // no need to do an animation.  This is the case, for
+        // example, when this transition is being done behind
+        // the lock screen.
+        if (!mService.mPolicy.allowAppAnimationsLw()) {
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Animations disallowed by keyguard or dream.");
+            animLp = null;
+        }
+
+        processApplicationsAnimatingInPlace(transit);
+
+        AppWindowToken topClosingApp = null;
+        int topClosingLayer = 0;
+        appsCount = mService.mClosingApps.size();
+        for (i = 0; i < appsCount; i++) {
+            AppWindowToken wtoken = mService.mClosingApps.valueAt(i);
+            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Now closing app " + wtoken);
+            appAnimator.clearThumbnail();
+            appAnimator.animation = null;
+            wtoken.inPendingTransaction = false;
+            mService.setTokenVisibilityLocked(wtoken, animLp, false, transit, false,
+                    voiceInteraction);
+            wtoken.updateReportedVisibilityLocked();
+            // Force the allDrawn flag, because we want to start
+            // this guy's animations regardless of whether it's
+            // gotten drawn.
+            wtoken.allDrawn = true;
+            wtoken.deferClearAllDrawn = false;
+            // Ensure that apps that are mid-starting are also scheduled to have their
+            // starting windows removed after the animation is complete
+            if (wtoken.startingWindow != null && !wtoken.startingWindow.mExiting) {
+                mService.scheduleRemoveStartingWindowLocked(wtoken);
+            }
+            mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+            if (animLp != null) {
+                int layer = -1;
+                for (int j = 0; j < wtoken.windows.size(); j++) {
+                    WindowState win = wtoken.windows.get(j);
+                    if (win.mWinAnimator.mAnimLayer > layer) {
+                        layer = win.mWinAnimator.mAnimLayer;
+                    }
+                }
+                if (topClosingApp == null || layer > topClosingLayer) {
+                    topClosingApp = wtoken;
+                    topClosingLayer = layer;
+                }
+            }
+        }
+
+        AppWindowToken topOpeningApp = null;
+        appsCount = mService.mOpeningApps.size();
+        for (i = 0; i < appsCount; i++) {
+            AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
+            final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "Now opening app" + wtoken);
+
+            if (!appAnimator.usingTransferredAnimation) {
+                appAnimator.clearThumbnail();
+                appAnimator.animation = null;
+            }
+            wtoken.inPendingTransaction = false;
+            if (!mService.setTokenVisibilityLocked(
+                    wtoken, animLp, true, transit, false, voiceInteraction)){
+                // This token isn't going to be animating. Add it to the list of tokens to
+                // be notified of app transition complete since the notification will not be
+                // sent be the app window animator.
+                mService.mNoAnimationNotifyOnTransitionFinished.add(wtoken.token);
+            }
+            wtoken.updateReportedVisibilityLocked();
+            wtoken.waitingToShow = false;
+
+            appAnimator.mAllAppWinAnimators.clear();
+            final int windowsCount = wtoken.allAppWindows.size();
+            for (int j = 0; j < windowsCount; j++) {
+                appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+            }
+            mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+
+            int topOpeningLayer = 0;
+            if (animLp != null) {
+                int layer = -1;
+                for (int j = 0; j < wtoken.windows.size(); j++) {
+                    WindowState win = wtoken.windows.get(j);
+                    if (win.mWinAnimator.mAnimLayer > layer) {
+                        layer = win.mWinAnimator.mAnimLayer;
+                    }
+                }
+                if (topOpeningApp == null || layer > topOpeningLayer) {
+                    topOpeningApp = wtoken;
+                    topOpeningLayer = layer;
+                }
+            }
+            createThumbnailAppAnimator(transit, wtoken, topOpeningLayer, topClosingLayer);
+        }
+
+        AppWindowAnimator openingAppAnimator = (topOpeningApp == null) ?  null :
+                topOpeningApp.mAppAnimator;
+        AppWindowAnimator closingAppAnimator = (topClosingApp == null) ? null :
+                topClosingApp.mAppAnimator;
+
+        mService.mAppTransition.goodToGo(openingAppAnimator, closingAppAnimator);
+        mService.mAppTransition.postAnimationCallback();
+        mService.mAppTransition.clear();
+
+        mService.mOpeningApps.clear();
+        mService.mClosingApps.clear();
+
+        // This has changed the visibility of windows, so perform
+        // a new layout to get them all up-to-date.
+        mService.getDefaultDisplayContentLocked().layoutNeeded = true;
+
+        // TODO(multidisplay): IMEs are only supported on the default display.
+        if (windows == mService.getDefaultWindowListLocked()
+                && !mService.moveInputMethodWindowsIfNeededLocked(true)) {
+            mService.assignLayersLocked(windows);
+        }
+        mService.updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES,
+                true /*updateInputWindows*/);
+        mService.mFocusMayChange = false;
+        mService.notifyActivityDrawnForKeyguard();
+        return FINISH_LAYOUT_REDO_LAYOUT
+                | FINISH_LAYOUT_REDO_CONFIG;
+
+    }
+
+    private boolean transitionGoodToGo(int appsCount) {
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                "Checking " + appsCount + " opening apps (frozen="
+                        + mService.mDisplayFrozen + " timeout="
+                        + mService.mAppTransition.isTimeout() + ")...");
+        if (!mService.mAppTransition.isTimeout()) {
+            for (int i = 0; i < appsCount; i++) {
+                AppWindowToken wtoken = mService.mOpeningApps.valueAt(i);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                        "Check opening app=" + wtoken + ": allDrawn="
+                        + wtoken.allDrawn + " startingDisplayed="
+                        + wtoken.startingDisplayed + " startingMoved="
+                        + wtoken.startingMoved);
+                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+                    return false;
+                }
+            }
+
+            // If the wallpaper is visible, we need to check it's ready too.
+            return !mWallpaperControllerLocked.isWallpaperVisible() ||
+                    mWallpaperControllerLocked.wallpaperTransitionReady();
+        }
+        return true;
+    }
+
+    private int maybeUpdateTransitToWallpaper(int transit, boolean openingAppHasWallpaper,
+            boolean closingAppHasWallpaper, WindowState lowerWallpaperTarget,
+            WindowState upperWallpaperTarget) {
+        // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper
+        final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget();
+        final WindowState oldWallpaper =
+                mWallpaperControllerLocked.isWallpaperTargetAnimating()
+                        ? null : wallpaperTarget;
+        if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                "New wallpaper target=" + wallpaperTarget
+                        + ", oldWallpaper=" + oldWallpaper
+                        + ", lower target=" + lowerWallpaperTarget
+                        + ", upper target=" + upperWallpaperTarget);
+        mService.mAnimateWallpaperWithTarget = false;
+        if (closingAppHasWallpaper && openingAppHasWallpaper) {
+            if (DEBUG_APP_TRANSITIONS)
+                Slog.v(TAG, "Wallpaper animation!");
+            switch (transit) {
+                case AppTransition.TRANSIT_ACTIVITY_OPEN:
+                case AppTransition.TRANSIT_TASK_OPEN:
+                case AppTransition.TRANSIT_TASK_TO_FRONT:
+                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_OPEN;
+                    break;
+                case AppTransition.TRANSIT_ACTIVITY_CLOSE:
+                case AppTransition.TRANSIT_TASK_CLOSE:
+                case AppTransition.TRANSIT_TASK_TO_BACK:
+                    transit = AppTransition.TRANSIT_WALLPAPER_INTRA_CLOSE;
+                    break;
+            }
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit: " + AppTransition.appTransitionToString(transit));
+        } else if ((oldWallpaper != null) && !mService.mOpeningApps.isEmpty()
+                && !mService.mOpeningApps.contains(oldWallpaper.mAppToken)) {
+            // We are transitioning from an activity with
+            // a wallpaper to one without.
+            transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit away from wallpaper: "
+                    + AppTransition.appTransitionToString(transit));
+        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+            // We are transitioning from an activity without
+            // a wallpaper to now showing the wallpaper
+            transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
+            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
+                    "New transit into wallpaper: "
+                    + AppTransition.appTransitionToString(transit));
+        } else {
+            mService.mAnimateWallpaperWithTarget = true;
+        }
+        return transit;
+    }
+
+    /**
+     * @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 int innerDw, final int innerDh) {
+        final WindowManager.LayoutParams attrs = w.mAttrs;
+        final int attrFlags = attrs.flags;
+        final boolean canBeSeen = w.isDisplayedLw();
+        final boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn();
+
+        if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) {
+            // This window completely covers everything behind it,
+            // so we want to leave all of them as undimmed (for
+            // performance reasons).
+            mObscured = true;
+        }
+
+        if (w.mHasSurface) {
+            if ((attrFlags&FLAG_KEEP_SCREEN_ON) != 0) {
+                mHoldScreen = w.mSession;
+            }
+            if (!mSyswin && w.mAttrs.screenBrightness >= 0
+                    && mScreenBrightness < 0) {
+                mScreenBrightness = w.mAttrs.screenBrightness;
+            }
+            if (!mSyswin && w.mAttrs.buttonBrightness >= 0
+                    && mButtonBrightness < 0) {
+                mButtonBrightness = w.mAttrs.buttonBrightness;
+            }
+            if (!mSyswin && w.mAttrs.userActivityTimeout >= 0
+                    && mUserActivityTimeout < 0) {
+                mUserActivityTimeout = w.mAttrs.userActivityTimeout;
+            }
+
+            final int type = attrs.type;
+            if (canBeSeen
+                    && (type == TYPE_SYSTEM_DIALOG
+                     || type == TYPE_SYSTEM_ERROR
+                     || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) {
+                mSyswin = true;
+            }
+
+            if (canBeSeen) {
+                // This function assumes that the contents of the default display are
+                // processed first before secondary displays.
+                final DisplayContent displayContent = w.getDisplayContent();
+                if (displayContent != null && displayContent.isDefaultDisplay) {
+                    // While a dream or keyguard is showing, obscure ordinary application
+                    // content on secondary displays (by forcibly enabling mirroring unless
+                    // there is other content we want to show) but still allow opaque
+                    // keyguard dialogs to be shown.
+                    if (type == TYPE_DREAM || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
+                        mObscureApplicationContentOnSecondaryDisplays = true;
+                    }
+                    mDisplayHasContent = true;
+                } else if (displayContent != null &&
+                        (!mObscureApplicationContentOnSecondaryDisplays
+                        || (mObscured && type == TYPE_KEYGUARD_DIALOG))) {
+                    // Allow full screen keyguard presentation dialogs to be seen.
+                    mDisplayHasContent = true;
+                }
+                if (mPreferredRefreshRate == 0
+                        && w.mAttrs.preferredRefreshRate != 0) {
+                    mPreferredRefreshRate = w.mAttrs.preferredRefreshRate;
+                }
+                if (mPreferredModeId == 0
+                        && w.mAttrs.preferredDisplayModeId != 0) {
+                    mPreferredModeId = w.mAttrs.preferredDisplayModeId;
+                }
+            }
+        }
+    }
+
+    private void updateAllDrawnLocked(DisplayContent displayContent) {
+        // See if any windows have been drawn, so they (and others
+        // associated with them) can now be shown.
+        ArrayList<TaskStack> stacks = displayContent.getStacks();
+        for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+            final ArrayList<Task> tasks = stacks.get(stackNdx).getTasks();
+            for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                final AppTokenList tokens = tasks.get(taskNdx).mAppTokens;
+                for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx) {
+                    final AppWindowToken wtoken = tokens.get(tokenNdx);
+                    if (!wtoken.allDrawn) {
+                        int numInteresting = wtoken.numInterestingWindows;
+                        if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) {
+                            if (DEBUG_VISIBILITY)
+                                Slog.v(TAG, "allDrawn: " + wtoken
+                                    + " interesting=" + numInteresting
+                                    + " drawn=" + wtoken.numDrawnWindows);
+                            wtoken.allDrawn = true;
+                            // Force an additional layout pass where WindowStateAnimator#
+                            // commitFinishDrawingLocked() will call performShowLocked().
+                            displayContent.layoutNeeded = true;
+                            mService.mH.obtainMessage(NOTIFY_ACTIVITY_DRAWN,
+                                    wtoken.token).sendToTarget();
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private static int toBrightnessOverride(float value) {
+        return (int)(value * PowerManager.BRIGHTNESS_ON);
+    }
+
+    private void processApplicationsAnimatingInPlace(int transit) {
+        if (transit == AppTransition.TRANSIT_TASK_IN_PLACE) {
+            // Find the focused window
+            final WindowState win = mService.findFocusedWindowLocked(
+                    mService.getDefaultDisplayContentLocked());
+            if (win != null) {
+                final AppWindowToken wtoken = win.mAppToken;
+                final AppWindowAnimator appAnimator = wtoken.mAppAnimator;
+                if (DEBUG_APP_TRANSITIONS)
+                    Slog.v(TAG, "Now animating app in place " + wtoken);
+                appAnimator.clearThumbnail();
+                appAnimator.animation = null;
+                mService.updateTokenInPlaceLocked(wtoken, transit);
+                wtoken.updateReportedVisibilityLocked();
+
+                appAnimator.mAllAppWinAnimators.clear();
+                final int N = wtoken.allAppWindows.size();
+                for (int j = 0; j < N; j++) {
+                    appAnimator.mAllAppWinAnimators.add(wtoken.allAppWindows.get(j).mWinAnimator);
+                }
+                mService.mAnimator.mAppWindowAnimating |= appAnimator.isAnimating();
+                mService.mAnimator.mAnimating |= appAnimator.showAllWindowsLocked();
+            }
+        }
+    }
+
+    private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
+            int openingLayer, int closingLayer) {
+        AppWindowAnimator openingAppAnimator = (appToken == null) ? null : appToken.mAppAnimator;
+        if (openingAppAnimator == null || openingAppAnimator.animation == null) {
+            return;
+        }
+        final int taskId = appToken.mTask.mTaskId;
+        Bitmap thumbnailHeader = mService.mAppTransition.getAppTransitionThumbnailHeader(taskId);
+        if (thumbnailHeader == null || thumbnailHeader.getConfig() == Bitmap.Config.ALPHA_8) {
+            return;
+        }
+        // This thumbnail animation is very special, we need to have
+        // an extra surface with the thumbnail included with the animation.
+        Rect dirty = new Rect(0, 0, thumbnailHeader.getWidth(), thumbnailHeader.getHeight());
+        try {
+            // TODO(multi-display): support other displays
+            final DisplayContent displayContent = mService.getDefaultDisplayContentLocked();
+            final Display display = displayContent.getDisplay();
+            final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+
+            // Create a new surface for the thumbnail
+            SurfaceControl surfaceControl = new SurfaceControl(mService.mFxSession,
+                    "thumbnail anim", dirty.width(), dirty.height(),
+                    PixelFormat.TRANSLUCENT, SurfaceControl.HIDDEN);
+            surfaceControl.setLayerStack(display.getLayerStack());
+            if (SHOW_TRANSACTIONS) {
+                Slog.i(TAG, "  THUMBNAIL " + surfaceControl + ": CREATE");
+            }
+
+            // Draw the thumbnail onto the surface
+            Surface drawSurface = new Surface();
+            drawSurface.copyFrom(surfaceControl);
+            Canvas c = drawSurface.lockCanvas(dirty);
+            c.drawBitmap(thumbnailHeader, 0, 0, null);
+            drawSurface.unlockCanvasAndPost(c);
+            drawSurface.release();
+
+            // Get the thumbnail animation
+            Animation anim;
+            if (mService.mAppTransition.isNextThumbnailTransitionAspectScaled()) {
+                // If this is a multi-window scenario, we use the windows frame as
+                // destination of the thumbnail header animation. If this is a full screen
+                // window scenario, we use the whole display as the target.
+                WindowState win = appToken.findMainWindow();
+                Rect appRect = win != null ? win.getContentFrameLw() :
+                        new Rect(0, 0, displayInfo.appWidth, displayInfo.appHeight);
+                // For the new aspect-scaled transition, we want it to always show
+                // above the animating opening/closing window, and we want to
+                // synchronize its thumbnail surface with the surface for the
+                // open/close animation (only on the way down)
+                anim = mService.mAppTransition.createThumbnailAspectScaleAnimationLocked(appRect,
+                        thumbnailHeader, taskId);
+                Log.d(TAG, "assigning thumbnail force above layer: "
+                        + openingLayer + " " + closingLayer);
+                openingAppAnimator.thumbnailForceAboveLayer = Math.max(openingLayer, closingLayer);
+                openingAppAnimator.deferThumbnailDestruction =
+                        !mService.mAppTransition.isNextThumbnailTransitionScaleUp();
+            } else {
+                anim = mService.mAppTransition.createThumbnailScaleAnimationLocked(
+                        displayInfo.appWidth, displayInfo.appHeight, transit, thumbnailHeader);
+            }
+            anim.restrictDuration(MAX_ANIMATION_DURATION);
+            anim.scaleCurrentDuration(mService.getTransitionAnimationScaleLocked());
+
+            openingAppAnimator.thumbnail = surfaceControl;
+            openingAppAnimator.thumbnailLayer = openingLayer;
+            openingAppAnimator.thumbnailAnimation = anim;
+            mService.mAppTransition.getNextAppTransitionStartRect(taskId, mTmpStartRect);
+            openingAppAnimator.thumbnailX = mTmpStartRect.left;
+            openingAppAnimator.thumbnailY = mTmpStartRect.top;
+        } catch (Surface.OutOfResourcesException e) {
+            Slog.e(TAG, "Can't allocate thumbnail/Canvas surface w="
+                    + dirty.width() + " h=" + dirty.height(), e);
+            openingAppAnimator.clearThumbnail();
+        }
+    }
+
+    boolean copyAnimToLayoutParamsLocked() {
+        boolean doRequest = false;
+
+        final int bulkUpdateParams = mService.mAnimator.mBulkUpdateParams;
+        if ((bulkUpdateParams & SET_UPDATE_ROTATION) != 0) {
+            mUpdateRotation = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_MAY_CHANGE) != 0) {
+            mWallpaperMayChange = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_FORCE_HIDING_CHANGED) != 0) {
+            mWallpaperForceHidingChanged = true;
+            doRequest = true;
+        }
+        if ((bulkUpdateParams & SET_ORIENTATION_CHANGE_COMPLETE) == 0) {
+            mOrientationChangeComplete = false;
+        } else {
+            mOrientationChangeComplete = true;
+            mLastWindowFreezeSource = mService.mAnimator.mLastWindowFreezeSource;
+            if (mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_NONE) {
+                doRequest = true;
+            }
+        }
+        if ((bulkUpdateParams & SET_TURN_ON_SCREEN) != 0) {
+            mService.mTurnOnScreen = true;
+        }
+        if ((bulkUpdateParams & SET_WALLPAPER_ACTION_PENDING) != 0) {
+            mWallpaperActionPending = true;
+        }
+
+        return doRequest;
+    }
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 9556b08..98d8d08 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -4,9 +4,16 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
 
+ifneq ($(ENABLE_CPUSETS),)
+ifneq ($(ENABLE_SCHED_BOOST),)
+LOCAL_CFLAGS += -DUSE_SCHED_BOOST
+endif
+endif
+
 LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_am_ActivityManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AssetAtlasService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
     $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
diff --git a/services/core/jni/com_android_server_am_ActivityManagerService.cpp b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
new file mode 100644
index 0000000..52217b9
--- /dev/null
+++ b/services/core/jni/com_android_server_am_ActivityManagerService.cpp
@@ -0,0 +1,151 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ActivityManagerService"
+//#define LOG_NDEBUG 0
+
+#include <android_runtime/AndroidRuntime.h>
+#include <jni.h>
+
+#include <ScopedLocalRef.h>
+#include <ScopedPrimitiveArray.h>
+
+#include <cutils/log.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android
+{
+
+    // migrate from foreground to foreground_boost
+    static jint migrateToBoost(JNIEnv *env, jobject _this)
+    {
+#ifdef USE_SCHED_BOOST
+        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+        FILE* fg_cpuset_file = NULL;
+        int   boost_cpuset_fd = 0;
+        if (!access("/dev/cpuset/tasks", F_OK)) {
+            fg_cpuset_file = fopen("/dev/cpuset/foreground/tasks", "r+");
+            if (ferror(fg_cpuset_file)) {
+                return 0;
+            }
+            boost_cpuset_fd = open("/dev/cpuset/foreground/boost/tasks", O_WRONLY);
+            if (boost_cpuset_fd < 0) {
+                fclose(fg_cpuset_file);
+                return 0;
+            }
+
+        }
+        if (!fg_cpuset_file || !boost_cpuset_fd) {
+            fclose(fg_cpuset_file);
+            close(boost_cpuset_fd);
+            return 0;
+        }
+        char buf[17];
+        while (fgets(buf, 16, fg_cpuset_file)) {
+            int i = 0;
+            for (; i < 16; i++) {
+                if (buf[i] == '\n') {
+                    buf[i] = 0;
+                    break;
+                }
+            }
+            if (write(boost_cpuset_fd, buf, i) < 0) {
+                // ignore error
+            }
+            if (feof(fg_cpuset_file))
+                break;
+        }
+        fclose(fg_cpuset_file);
+        close(boost_cpuset_fd);
+#endif
+        return 0;
+    }
+
+    // migrate from foreground_boost to foreground
+    static jint migrateFromBoost(JNIEnv *env, jobject _this)
+    {
+#ifdef USE_SCHED_BOOST
+        // File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error
+        int   fg_cpuset_fd = 0;
+        FILE* boost_cpuset_file = NULL;
+        if (!access("/dev/cpuset/tasks", F_OK)) {
+            boost_cpuset_file = fopen("/dev/cpuset/foreground/boost/tasks", "r+");
+            if (ferror(boost_cpuset_file)) {
+                return 0;
+            }
+            fg_cpuset_fd = open("/dev/cpuset/foreground/tasks", O_WRONLY);
+            if (fg_cpuset_fd < 0) {
+                fclose(boost_cpuset_file);
+                return 0;
+            }
+
+        }
+        if (!boost_cpuset_file || !fg_cpuset_fd) {
+            fclose(boost_cpuset_file);
+            close(fg_cpuset_fd);
+            return 0;
+        }
+        char buf[17];
+        char *curBuf = buf;
+        while (fgets(buf, 16, boost_cpuset_file)) {
+            //ALOGE("Appending FD %s to fg", buf);
+            int i = 0;
+            for (; i < 16; i++) {
+                if (buf[i] == '\n') {
+                    buf[i] = 0;
+                    break;
+                }
+            }
+            if (write(fg_cpuset_fd, buf, i) < 0) {
+                //ALOGE("Appending FD %s to fg ERROR", buf);
+                // handle error?
+            }
+            if (feof(boost_cpuset_file))
+                break;
+        }
+
+        close(fg_cpuset_fd);
+        fclose(boost_cpuset_file);
+
+#endif
+        return 0;
+
+    }
+
+
+    static JNINativeMethod method_table[] = {
+        { "nativeMigrateToBoost",   "()I", (void*)migrateToBoost },
+        { "nativeMigrateFromBoost", "()I", (void*)migrateFromBoost },
+    };
+
+    int register_android_server_ActivityManagerService(JNIEnv *env)
+    {
+        return jniRegisterNativeMethods(env, "com/android/server/am/ActivityManagerService",
+                                        method_table, NELEM(method_table));
+    }
+
+}
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 2ca5f5a..c0a0c9c 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -840,16 +840,6 @@
     env->DeleteGlobalRef(sCallbacksObj);
     sCallbacksObj = NULL;
   }
-
-  sFlpInterface = NULL;
-  sFlpDiagnosticInterface = NULL;
-  sFlpDeviceContextInterface = NULL;
-  sFlpGeofencingInterface = NULL;
-
-  if(sHardwareDevice != NULL) {
-    sHardwareDevice->close(sHardwareDevice);
-    sHardwareDevice = NULL;
-  }
 }
 
 static void GetBatchedLocation(JNIEnv* env, jobject /* object */, jint lastNLocations) {
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 67872da..1f3fde6 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -20,6 +20,7 @@
 #include "utils/misc.h"
 
 namespace android {
+int register_android_server_ActivityManagerService(JNIEnv* env);
 int register_android_server_AlarmManagerService(JNIEnv* env);
 int register_android_server_AssetAtlasService(JNIEnv* env);
 int register_android_server_BatteryStatsService(JNIEnv* env);
@@ -57,6 +58,7 @@
     }
     ALOG_ASSERT(env, "Could not retrieve the env!");
 
+    register_android_server_ActivityManagerService(env);
     register_android_server_PowerManagerService(env);
     register_android_server_SerialService(env);
     register_android_server_InputApplicationHandle(env);
@@ -80,5 +82,6 @@
     register_android_server_PersistentDataBlockService(env);
     register_android_server_Watchdog(env);
 
+
     return JNI_VERSION_1_4;
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
deleted file mode 100644
index 7bd27f2..0000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.devicepolicy;
-
-import android.app.AppGlobals;
-import android.app.admin.SystemUpdatePolicy;
-import android.content.ComponentName;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Environment;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-import android.util.AtomicFile;
-import android.util.Slog;
-import android.util.Xml;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.FastXmlSerializer;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.nio.charset.StandardCharsets;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Stores and restores state for the Device and Profile owners. By definition there can be
- * only one device owner, but there may be a profile owner for each user.
- */
-class DeviceOwner {
-    private static final String TAG = "DevicePolicyManagerService";
-
-    private static final String DEVICE_OWNER_XML = "device_owner.xml";
-    private static final String TAG_DEVICE_OWNER = "device-owner";
-    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
-    private static final String TAG_PROFILE_OWNER = "profile-owner";
-    private static final String ATTR_NAME = "name";
-    private static final String ATTR_PACKAGE = "package";
-    private static final String ATTR_COMPONENT_NAME = "component";
-    private static final String ATTR_USERID = "userId";
-    private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
-
-    private AtomicFile fileForWriting;
-
-    // Input/Output streams for testing.
-    private InputStream mInputStreamForTest;
-    private OutputStream mOutputStreamForTest;
-
-    // Internal state for the device owner package.
-    private OwnerInfo mDeviceOwner;
-
-    // Internal state for the device initializer package.
-    private OwnerInfo mDeviceInitializer;
-
-    // Internal state for the profile owner packages.
-    private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
-
-    // Local system update policy controllable by device owner.
-    private SystemUpdatePolicy mSystemUpdatePolicy;
-
-    // Private default constructor.
-    private DeviceOwner() {
-    }
-
-    @VisibleForTesting
-    DeviceOwner(InputStream in, OutputStream out) {
-        mInputStreamForTest = in;
-        mOutputStreamForTest = out;
-    }
-
-    /**
-     * Loads the device owner state from disk.
-     */
-    static DeviceOwner load() {
-        DeviceOwner owner = new DeviceOwner();
-        if (new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML).exists()) {
-            owner.readOwnerFile();
-            return owner;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * Creates an instance of the device owner object with the device owner set.
-     */
-    static DeviceOwner createWithDeviceOwner(String packageName, String ownerName) {
-        DeviceOwner owner = new DeviceOwner();
-        owner.mDeviceOwner = new OwnerInfo(ownerName, packageName);
-        return owner;
-    }
-
-    /**
-     * Creates an instance of the device owner object with the device initializer set.
-     */
-    static DeviceOwner createWithDeviceInitializer(ComponentName admin) {
-        DeviceOwner owner = new DeviceOwner();
-        owner.mDeviceInitializer = new OwnerInfo(null, admin);
-        return owner;
-    }
-
-    /**
-     * Creates an instance of the device owner object with the profile owner set.
-     */
-    static DeviceOwner createWithProfileOwner(ComponentName admin, String ownerName, int userId) {
-        DeviceOwner owner = new DeviceOwner();
-        owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
-        return owner;
-    }
-
-    String getDeviceOwnerPackageName() {
-        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
-    }
-
-    String getDeviceOwnerName() {
-        return mDeviceOwner != null ? mDeviceOwner.name : null;
-    }
-
-    void setDeviceOwner(String packageName, String ownerName) {
-        mDeviceOwner = new OwnerInfo(ownerName, packageName);
-    }
-
-    void clearDeviceOwner() {
-        mDeviceOwner = null;
-    }
-
-    ComponentName getDeviceInitializerComponent() {
-        return mDeviceInitializer.admin;
-    }
-
-    String getDeviceInitializerPackageName() {
-        return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
-    }
-
-    void setDeviceInitializer(ComponentName admin) {
-        mDeviceInitializer = new OwnerInfo(null, admin);
-    }
-
-    void clearDeviceInitializer() {
-        mDeviceInitializer = null;
-    }
-
-    boolean hasDeviceInitializer() {
-        return mDeviceInitializer != null;
-    }
-
-    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
-        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
-    }
-
-    void removeProfileOwner(int userId) {
-        mProfileOwners.remove(userId);
-    }
-
-    ComponentName getProfileOwnerComponent(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.admin : null;
-    }
-
-    String getProfileOwnerName(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.name : null;
-    }
-
-    Set<Integer> getProfileOwnerKeys() {
-        return mProfileOwners.keySet();
-    }
-
-    SystemUpdatePolicy getSystemUpdatePolicy() {
-        return mSystemUpdatePolicy;
-    }
-
-    void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
-        mSystemUpdatePolicy = systemUpdatePolicy;
-    }
-
-    void clearSystemUpdatePolicy() {
-        mSystemUpdatePolicy = null;
-    }
-
-    boolean hasDeviceOwner() {
-        return mDeviceOwner != null;
-    }
-
-    static boolean isInstalled(String packageName, PackageManager pm) {
-        try {
-            PackageInfo pi;
-            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
-                if ((pi.applicationInfo.flags) != 0) {
-                    return true;
-                }
-            }
-        } catch (NameNotFoundException nnfe) {
-            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
-        }
-        return false;
-    }
-
-    static boolean isInstalledForUser(String packageName, int userHandle) {
-        try {
-            PackageInfo pi = (AppGlobals.getPackageManager())
-                    .getPackageInfo(packageName, 0, userHandle);
-            if (pi != null && pi.applicationInfo.flags != 0) {
-                return true;
-            }
-        } catch (RemoteException re) {
-            throw new RuntimeException("Package manager has died", re);
-        }
-
-        return false;
-    }
-
-    @VisibleForTesting
-    void readOwnerFile() {
-        try {
-            InputStream input = openRead();
-            XmlPullParser parser = Xml.newPullParser();
-            parser.setInput(input, StandardCharsets.UTF_8.name());
-            int type;
-            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
-                if (type!=XmlPullParser.START_TAG) {
-                    continue;
-                }
-
-                String tag = parser.getName();
-                if (tag.equals(TAG_DEVICE_OWNER)) {
-                    String name = parser.getAttributeValue(null, ATTR_NAME);
-                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    mDeviceOwner = new OwnerInfo(name, packageName);
-                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
-                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    String initializerComponentStr =
-                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
-                    ComponentName admin =
-                            ComponentName.unflattenFromString(initializerComponentStr);
-                    if (admin != null) {
-                        mDeviceInitializer = new OwnerInfo(null, admin);
-                    } else {
-                        mDeviceInitializer = new OwnerInfo(null, packageName);
-                        Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
-                                initializerComponentStr);
-                    }
-                } else if (tag.equals(TAG_PROFILE_OWNER)) {
-                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
-                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
-                    String profileOwnerComponentStr =
-                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
-                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
-                    OwnerInfo profileOwnerInfo = null;
-                    if (profileOwnerComponentStr != null) {
-                        ComponentName admin = ComponentName.unflattenFromString(
-                                profileOwnerComponentStr);
-                        if (admin != null) {
-                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin);
-                        } else {
-                            // This shouldn't happen but switch from package name -> component name
-                            // might have written bad device owner files. b/17652534
-                            Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
-                                    profileOwnerComponentStr);
-                        }
-                    }
-                    if (profileOwnerInfo == null) {
-                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
-                    }
-                    mProfileOwners.put(userId, profileOwnerInfo);
-                } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
-                    mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
-                } else {
-                    throw new XmlPullParserException(
-                            "Unexpected tag in device owner file: " + tag);
-                }
-            }
-            input.close();
-        } catch (XmlPullParserException xppe) {
-            Slog.e(TAG, "Error parsing device-owner file\n" + xppe);
-        } catch (IOException ioe) {
-            Slog.e(TAG, "IO Exception when reading device-owner file\n" + ioe);
-        }
-    }
-
-    @VisibleForTesting
-    void writeOwnerFile() {
-        synchronized (this) {
-            writeOwnerFileLocked();
-        }
-    }
-
-    private void writeOwnerFileLocked() {
-        try {
-            OutputStream outputStream = startWrite();
-            XmlSerializer out = new FastXmlSerializer();
-            out.setOutput(outputStream, StandardCharsets.UTF_8.name());
-            out.startDocument(null, true);
-
-            // Write device owner tag
-            if (mDeviceOwner != null) {
-                out.startTag(null, TAG_DEVICE_OWNER);
-                out.attribute(null, ATTR_PACKAGE, mDeviceOwner.packageName);
-                if (mDeviceOwner.name != null) {
-                    out.attribute(null, ATTR_NAME, mDeviceOwner.name);
-                }
-                out.endTag(null, TAG_DEVICE_OWNER);
-            }
-
-            // Write device initializer tag
-            if (mDeviceInitializer != null) {
-                out.startTag(null, TAG_DEVICE_INITIALIZER);
-                out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
-                if (mDeviceInitializer.admin != null) {
-                    out.attribute(
-                            null, ATTR_COMPONENT_NAME, mDeviceInitializer.admin.flattenToString());
-                }
-                out.endTag(null, TAG_DEVICE_INITIALIZER);
-            }
-
-            // Write profile owner tags
-            if (mProfileOwners.size() > 0) {
-                for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {
-                    out.startTag(null, TAG_PROFILE_OWNER);
-                    OwnerInfo ownerInfo = owner.getValue();
-                    out.attribute(null, ATTR_PACKAGE, ownerInfo.packageName);
-                    out.attribute(null, ATTR_NAME, ownerInfo.name);
-                    out.attribute(null, ATTR_USERID, Integer.toString(owner.getKey()));
-                    if (ownerInfo.admin != null) {
-                        out.attribute(null, ATTR_COMPONENT_NAME, ownerInfo.admin.flattenToString());
-                    }
-                    out.endTag(null, TAG_PROFILE_OWNER);
-                }
-            }
-
-            // Write system update policy tag
-            if (mSystemUpdatePolicy != null) {
-                out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
-                mSystemUpdatePolicy.saveToXml(out);
-                out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
-            }
-            out.endDocument();
-            out.flush();
-            finishWrite(outputStream);
-        } catch (IOException ioe) {
-            Slog.e(TAG, "IO Exception when writing device-owner file\n" + ioe);
-        }
-    }
-
-    private InputStream openRead() throws IOException {
-        if (mInputStreamForTest != null) {
-            return mInputStreamForTest;
-        }
-
-        return new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                DEVICE_OWNER_XML)).openRead();
-    }
-
-    private OutputStream startWrite() throws IOException {
-        if (mOutputStreamForTest != null) {
-            return mOutputStreamForTest;
-        }
-
-        fileForWriting = new AtomicFile(new File(Environment.getSystemSecureDirectory(),
-                DEVICE_OWNER_XML));
-        return fileForWriting.startWrite();
-    }
-
-    private void finishWrite(OutputStream stream) {
-        if (fileForWriting != null) {
-            fileForWriting.finishWrite((FileOutputStream) stream);
-        }
-    }
-
-    private static class OwnerInfo {
-        public final String name;
-        public final String packageName;
-        public final ComponentName admin;
-
-        public OwnerInfo(String name, String packageName) {
-            this.name = name;
-            this.packageName = packageName;
-            this.admin = new ComponentName(packageName, "");
-        }
-
-        public OwnerInfo(String name, ComponentName admin) {
-            this.name = name;
-            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 0f60cc8..0202309 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -45,7 +45,6 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SystemUpdatePolicy;
 import android.app.backup.IBackupManager;
-import android.app.trust.TrustManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -97,6 +96,8 @@
 import android.security.KeyChain.KeyChainConnection;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
@@ -141,8 +142,6 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
@@ -198,7 +197,7 @@
 
     private static final Set<String> DEVICE_OWNER_USER_RESTRICTIONS;
     static {
-        DEVICE_OWNER_USER_RESTRICTIONS = new HashSet();
+        DEVICE_OWNER_USER_RESTRICTIONS = new ArraySet<>();
         DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_USB_FILE_TRANSFER);
         DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_CONFIG_TETHERING);
         DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_NETWORK_RESET);
@@ -219,7 +218,7 @@
     // owner and profile owner.
     private static final Set<String> IMMUTABLE_USER_RESTRICTIONS;
     static {
-        IMMUTABLE_USER_RESTRICTIONS = new HashSet();
+        IMMUTABLE_USER_RESTRICTIONS = new ArraySet<>();
         IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER);
     }
 
@@ -228,16 +227,16 @@
     private static final Set<String> GLOBAL_SETTINGS_WHITELIST;
     private static final Set<String> GLOBAL_SETTINGS_DEPRECATED;
     static {
-        SECURE_SETTINGS_WHITELIST = new HashSet();
+        SECURE_SETTINGS_WHITELIST = new ArraySet<>();
         SECURE_SETTINGS_WHITELIST.add(Settings.Secure.DEFAULT_INPUT_METHOD);
         SECURE_SETTINGS_WHITELIST.add(Settings.Secure.SKIP_FIRST_USE_HINTS);
         SECURE_SETTINGS_WHITELIST.add(Settings.Secure.INSTALL_NON_MARKET_APPS);
 
-        SECURE_SETTINGS_DEVICEOWNER_WHITELIST = new HashSet();
+        SECURE_SETTINGS_DEVICEOWNER_WHITELIST = new ArraySet<>();
         SECURE_SETTINGS_DEVICEOWNER_WHITELIST.addAll(SECURE_SETTINGS_WHITELIST);
         SECURE_SETTINGS_DEVICEOWNER_WHITELIST.add(Settings.Secure.LOCATION_MODE);
 
-        GLOBAL_SETTINGS_WHITELIST = new HashSet();
+        GLOBAL_SETTINGS_WHITELIST = new ArraySet<>();
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE);
@@ -247,7 +246,7 @@
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
         GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
 
-        GLOBAL_SETTINGS_DEPRECATED = new HashSet();
+        GLOBAL_SETTINGS_DEPRECATED = new ArraySet<>();
         GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.BLUETOOTH_ON);
         GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);
         GLOBAL_SETTINGS_DEPRECATED.add(Settings.Global.MODE_RINGER);
@@ -279,7 +278,7 @@
     NotificationManager mNotificationManager;
 
     // Stores and loads state on device and profile owners.
-    private DeviceOwner mDeviceOwner;
+    private final Owners mOwners;
 
     private final Binder mToken = new Binder();
 
@@ -327,7 +326,7 @@
         boolean mUserSetupComplete = false;
         int mPermissionPolicy;
 
-        final HashMap<ComponentName, ActiveAdmin> mAdminMap = new HashMap<>();
+        final ArrayMap<ComponentName, ActiveAdmin> mAdminMap = new ArrayMap<>();
         final ArrayList<ActiveAdmin> mAdminList = new ArrayList<>();
         final ArrayList<ComponentName> mRemovingAdmins = new ArrayList<>();
 
@@ -495,7 +494,7 @@
             }
         }
 
-        Set<String> accountTypesWithManagementDisabled = new HashSet<String>();
+        Set<String> accountTypesWithManagementDisabled = new ArraySet<>();
 
         // The list of permitted accessibility services package namesas set by a profile
         // or device owner. Null means all accessibility services are allowed, empty means
@@ -512,7 +511,7 @@
         String globalProxySpec = null;
         String globalProxyExclusionList = null;
 
-        HashMap<String, TrustAgentInfo> trustAgentInfos = new HashMap<String, TrustAgentInfo>();
+        ArrayMap<String, TrustAgentInfo> trustAgentInfos = new ArrayMap<>();
 
         List<String> crossProfileWidgetProviders;
 
@@ -835,7 +834,7 @@
                 throws XmlPullParserException, IOException {
             int outerDepthDAM = parser.getDepth();
             int typeDAM;
-            Set<String> result = new HashSet<String>();
+            Set<String> result = new ArraySet<>();
             while ((typeDAM=parser.next()) != END_DOCUMENT
                     && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) {
                 if (typeDAM == END_TAG || typeDAM == TEXT) {
@@ -851,11 +850,11 @@
             return result;
         }
 
-        private HashMap<String, TrustAgentInfo> getAllTrustAgentInfos(
+        private ArrayMap<String, TrustAgentInfo> getAllTrustAgentInfos(
                 XmlPullParser parser, String tag) throws XmlPullParserException, IOException {
             int outerDepthDAM = parser.getDepth();
             int typeDAM;
-            HashMap<String, TrustAgentInfo> result = new HashMap<String, TrustAgentInfo>();
+            final ArrayMap<String, TrustAgentInfo> result = new ArrayMap<>();
             while ((typeDAM=parser.next()) != END_DOCUMENT
                     && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) {
                 if (typeDAM == END_TAG || typeDAM == TEXT) {
@@ -1044,6 +1043,7 @@
      */
     public DevicePolicyManagerService(Context context) {
         mContext = context;
+        mOwners = new Owners(mContext);
         mUserManager = UserManager.get(mContext);
         mHasFeature = context.getPackageManager().hasSystemFeature(
                 PackageManager.FEATURE_DEVICE_ADMIN);
@@ -1119,10 +1119,8 @@
                 Slog.w(LOG_TAG, "Tried to remove device policy file for user 0! Ignoring.");
                 return;
             }
-            if (mDeviceOwner != null) {
-                mDeviceOwner.removeProfileOwner(userHandle);
-                mDeviceOwner.writeOwnerFile();
-            }
+            mOwners.removeProfileOwner(userHandle);
+            mOwners.writeProfileOwner(userHandle);
 
             DevicePolicyData policy = mUserData.get(userHandle);
             if (policy != null) {
@@ -1138,7 +1136,7 @@
 
     void loadDeviceOwner() {
         synchronized (this) {
-            mDeviceOwner = DeviceOwner.load();
+            mOwners.load();
             updateDeviceOwnerLocked();
         }
     }
@@ -1806,16 +1804,15 @@
         Set<Integer> usersWithProfileOwners;
         Set<Integer> usersWithData;
         synchronized(this) {
-            usersWithProfileOwners = mDeviceOwner != null
-                    ? mDeviceOwner.getProfileOwnerKeys() : new HashSet<Integer>();
-            usersWithData = new HashSet<Integer>();
+            usersWithProfileOwners = mOwners.getProfileOwnerKeys();
+            usersWithData = new ArraySet<>();
             for (int i = 0; i < mUserData.size(); i++) {
                 usersWithData.add(mUserData.keyAt(i));
             }
         }
         List<UserInfo> allUsers = mUserManager.getUsers();
 
-        Set<Integer> deletedUsers = new HashSet<Integer>();
+        Set<Integer> deletedUsers = new ArraySet<>();
         deletedUsers.addAll(usersWithProfileOwners);
         deletedUsers.addAll(usersWithData);
         for (UserInfo userInfo : allUsers) {
@@ -4118,7 +4115,7 @@
             return false;
         }
         if (packageName == null
-                || !DeviceOwner.isInstalled(packageName, mContext.getPackageManager())) {
+                || !Owners.isInstalled(packageName, mContext.getPackageManager())) {
             throw new IllegalArgumentException("Invalid package name " + packageName
                     + " for device owner");
         }
@@ -4137,14 +4134,8 @@
                 Binder.restoreCallingIdentity(ident);
             }
 
-            if (mDeviceOwner == null) {
-                // Device owner is not set and does not exist, set it.
-                mDeviceOwner = DeviceOwner.createWithDeviceOwner(packageName, ownerName);
-            } else {
-                // Device owner state already exists, update it.
-                mDeviceOwner.setDeviceOwner(packageName, ownerName);
-            }
-            mDeviceOwner.writeOwnerFile();
+            mOwners.setDeviceOwner(packageName, ownerName);
+            mOwners.writeDeviceOwner();
             updateDeviceOwnerLocked();
             Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
 
@@ -4164,9 +4155,8 @@
             return false;
         }
         synchronized (this) {
-            return mDeviceOwner != null
-                    && mDeviceOwner.hasDeviceOwner()
-                    && mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
+            return mOwners.hasDeviceOwner()
+                    && mOwners.getDeviceOwnerPackageName().equals(packageName);
         }
     }
 
@@ -4176,11 +4166,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
-                return mDeviceOwner.getDeviceOwnerPackageName();
-            }
+            return mOwners.getDeviceOwnerPackageName();
         }
-        return null;
     }
 
     @Override
@@ -4190,10 +4177,10 @@
         }
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         synchronized (this) {
-            if (mDeviceOwner == null || !mDeviceOwner.hasDeviceOwner()) {
+            if (!mOwners.hasDeviceOwner()) {
                 return null;
             }
-            String deviceOwnerPackage = mDeviceOwner.getDeviceOwnerPackageName();
+            String deviceOwnerPackage = mOwners.getDeviceOwnerPackageName();
             return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_OWNER);
         }
     }
@@ -4232,10 +4219,20 @@
         }
         synchronized (this) {
             clearUserPoliciesLocked(new UserHandle(UserHandle.USER_OWNER));
-            if (mDeviceOwner != null) {
-                mDeviceOwner.clearDeviceOwner();
-                mDeviceOwner.writeOwnerFile();
-                updateDeviceOwnerLocked();
+
+            mOwners.clearDeviceOwner();
+            mOwners.writeDeviceOwner();
+            updateDeviceOwnerLocked();
+            // Reactivate backup service.
+            long ident = Binder.clearCallingIdentity();
+            try {
+                IBackupManager ibm = IBackupManager.Stub.asInterface(
+                        ServiceManager.getService(Context.BACKUP_SERVICE));
+                ibm.setBackupServiceActive(UserHandle.USER_OWNER, true);
+            } catch (RemoteException e) {
+                throw new IllegalStateException("Failed reactivating backup service.", e);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
             }
         }
     }
@@ -4245,7 +4242,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (initializer == null || !DeviceOwner.isInstalled(
+        if (initializer == null || !Owners.isInstalled(
                 initializer.getPackageName(), mContext.getPackageManager())) {
             throw new IllegalArgumentException("Invalid component name " + initializer
                     + " for device initializer");
@@ -4264,21 +4261,15 @@
         synchronized (this) {
             enforceCanSetDeviceInitializer(who);
 
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
+            if (mOwners.hasDeviceInitializer()) {
                 throw new IllegalStateException(
                         "Trying to set device initializer but device initializer is already set.");
             }
 
-            if (mDeviceOwner == null) {
-                // Device owner state does not exist, create it.
-                mDeviceOwner = DeviceOwner.createWithDeviceInitializer(initializer);
-            } else {
-                // Device owner already exists, update it.
-                mDeviceOwner.setDeviceInitializer(initializer);
-            }
+            mOwners.setDeviceInitializer(initializer);
 
             addDeviceInitializerToLockTaskPackagesLocked(UserHandle.USER_OWNER);
-            mDeviceOwner.writeOwnerFile();
+            mOwners.writeDeviceOwner();
             return true;
         }
     }
@@ -4302,9 +4293,8 @@
             return false;
         }
         synchronized (this) {
-            return mDeviceOwner != null
-                    && mDeviceOwner.hasDeviceInitializer()
-                    && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+            return mOwners.hasDeviceInitializer()
+                    && mOwners.getDeviceInitializerPackageName().equals(packageName);
         }
     }
 
@@ -4314,8 +4304,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
-                return mDeviceOwner.getDeviceInitializerPackageName();
+            if (mOwners.hasDeviceInitializer()) {
+                return mOwners.getDeviceInitializerPackageName();
             }
         }
         return null;
@@ -4327,8 +4317,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
-                return mDeviceOwner.getDeviceInitializerComponent();
+            if (mOwners.hasDeviceInitializer()) {
+                return mOwners.getDeviceInitializerComponent();
             }
         }
         return null;
@@ -4356,10 +4346,8 @@
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
-                if (mDeviceOwner != null) {
-                    mDeviceOwner.clearDeviceInitializer();
-                    mDeviceOwner.writeOwnerFile();
-                }
+                mOwners.clearDeviceInitializer();
+                mOwners.writeDeviceOwner();
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -4372,21 +4360,14 @@
             return false;
         }
         if (who == null
-                || !DeviceOwner.isInstalledForUser(who.getPackageName(), userHandle)) {
+                || !Owners.isInstalledForUser(who.getPackageName(), userHandle)) {
             throw new IllegalArgumentException("Component " + who
                     + " not installed for userId:" + userHandle);
         }
         synchronized (this) {
             enforceCanSetProfileOwner(userHandle);
-            if (mDeviceOwner == null) {
-                // Device owner state does not exist, create it.
-                mDeviceOwner = DeviceOwner.createWithProfileOwner(who, ownerName,
-                        userHandle);
-            } else {
-                // Device owner state already exists, update it.
-                mDeviceOwner.setProfileOwner(who, ownerName, userHandle);
-            }
-            mDeviceOwner.writeOwnerFile();
+            mOwners.setProfileOwner(who, ownerName, userHandle);
+            mOwners.writeProfileOwner(userHandle);
             return true;
         }
     }
@@ -4401,10 +4382,9 @@
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         synchronized (this) {
             clearUserPoliciesLocked(callingUser);
-            if (mDeviceOwner != null) {
-                mDeviceOwner.removeProfileOwner(callingUser.getIdentifier());
-                mDeviceOwner.writeOwnerFile();
-            }
+            final int userId = callingUser.getIdentifier();
+            mOwners.removeProfileOwner(userId);
+            mOwners.writeProfileOwner(userId);
         }
     }
 
@@ -4561,18 +4541,14 @@
         }
 
         synchronized (this) {
-            if (mDeviceOwner != null) {
-                return mDeviceOwner.getProfileOwnerComponent(userHandle);
-            }
+            return mOwners.getProfileOwnerComponent(userHandle);
         }
-        return null;
     }
 
     // Returns the active profile owner for this user or null if the current user has no
     // profile owner.
     private ActiveAdmin getProfileOwnerAdmin(int userHandle) {
-        ComponentName profileOwner =
-                mDeviceOwner != null ? mDeviceOwner.getProfileOwnerComponent(userHandle) : null;
+        ComponentName profileOwner = mOwners.getProfileOwnerComponent(userHandle);
         if (profileOwner == null) {
             return null;
         }
@@ -4673,7 +4649,7 @@
      * except for adb if no accounts or additional users are present on the device.
      */
     private void enforceCanSetDeviceOwner() {
-        if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
+        if (mOwners != null && mOwners.hasDeviceOwner()) {
             throw new IllegalStateException("Trying to set the device owner, but device owner "
                     + "is already set.");
         }
@@ -4774,9 +4750,7 @@
 
         synchronized (this) {
             p.println("Current Device Policy Manager state:");
-            if (mDeviceOwner != null) {
-                mDeviceOwner.dump("  ", pw);
-            }
+            mOwners.dump("  ", pw);
             int userCount = mUserData.size();
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -5722,7 +5696,7 @@
         synchronized (this) {
             DevicePolicyData policy = getUserData(userId);
             final int N = policy.mAdminList.size();
-            HashSet<String> resultSet = new HashSet<String>();
+            ArraySet<String> resultSet = new ArraySet<>();
             for (int i = 0; i < N; i++) {
                 ActiveAdmin admin = policy.mAdminList.get(i);
                 resultSet.addAll(admin.accountTypesWithManagementDisabled);
@@ -6263,10 +6237,10 @@
         @Override
         public List<String> getCrossProfileWidgetProviders(int profileId) {
             synchronized (DevicePolicyManagerService.this) {
-                if (mDeviceOwner == null) {
+                if (mOwners == null) {
                     return Collections.emptyList();
                 }
-                ComponentName ownerComponent = mDeviceOwner.getProfileOwnerComponent(profileId);
+                ComponentName ownerComponent = mOwners.getProfileOwnerComponent(profileId);
                 if (ownerComponent == null) {
                     return Collections.emptyList();
                 }
@@ -6336,11 +6310,11 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             if (policy == null) {
-                mDeviceOwner.clearSystemUpdatePolicy();
+                mOwners.clearSystemUpdatePolicy();
             } else {
-                mDeviceOwner.setSystemUpdatePolicy(policy);
+                mOwners.setSystemUpdatePolicy(policy);
             }
-            mDeviceOwner.writeOwnerFile();
+            mOwners.writeDeviceOwner();
         }
         mContext.sendBroadcastAsUser(
                 new Intent(DevicePolicyManager.ACTION_SYSTEM_UPDATE_POLICY_CHANGED),
@@ -6350,7 +6324,7 @@
     @Override
     public SystemUpdatePolicy getSystemUpdatePolicy() {
         synchronized (this) {
-            SystemUpdatePolicy policy =  mDeviceOwner.getSystemUpdatePolicy();
+            SystemUpdatePolicy policy =  mOwners.getSystemUpdatePolicy();
             if (policy != null && !policy.isValid()) {
                 Slog.w(LOG_TAG, "Stored system update policy is invalid, return null instead.");
                 return null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
new file mode 100644
index 0000000..1656716
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -0,0 +1,625 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.app.AppGlobals;
+import android.app.admin.SystemUpdatePolicy;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.os.Environment;
+import android.os.RemoteException;
+import android.os.UserManager;
+import android.util.ArrayMap;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Slog;
+import android.util.Xml;
+
+import com.android.internal.util.FastXmlSerializer;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import libcore.io.IoUtils;
+
+/**
+ * Stores and restores state for the Device and Profile owners. By definition there can be
+ * only one device owner, but there may be a profile owner for each user.
+ */
+class Owners {
+    private static final String TAG = "DevicePolicyManagerService";
+
+    private static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE
+
+    private static final String DEVICE_OWNER_XML_LEGACY = "device_owner.xml";
+
+    private static final String DEVICE_OWNER_XML = "device_owner_2.xml";
+
+    private static final String PROFILE_OWNER_XML = "profile_owner.xml";
+
+    private static final String TAG_ROOT = "root";
+
+    private static final String TAG_DEVICE_OWNER = "device-owner";
+    private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
+    private static final String TAG_PROFILE_OWNER = "profile-owner";
+
+    private static final String ATTR_NAME = "name";
+    private static final String ATTR_PACKAGE = "package";
+    private static final String ATTR_COMPONENT_NAME = "component";
+    private static final String ATTR_USERID = "userId";
+
+    private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
+
+    private final Context mContext;
+    private final UserManager mUserManager;
+
+    // Internal state for the device owner package.
+    private OwnerInfo mDeviceOwner;
+
+    // Internal state for the device initializer package.
+    private OwnerInfo mDeviceInitializer;
+
+    // Internal state for the profile owner packages.
+    private final ArrayMap<Integer, OwnerInfo> mProfileOwners = new ArrayMap<>();
+
+    // Local system update policy controllable by device owner.
+    private SystemUpdatePolicy mSystemUpdatePolicy;
+
+    public Owners(Context context) {
+        mContext = context;
+        mUserManager = UserManager.get(mContext);
+    }
+
+    /**
+     * Load configuration from the disk.
+     */
+    void load() {
+        synchronized (this) {
+            // First, try to read from the legacy file.
+            final File legacy = getLegacyConfigFileWithTestOverride();
+
+            if (readLegacyOwnerFile(legacy)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Legacy config file found.");
+                }
+
+                // Legacy file exists, write to new files and remove the legacy one.
+                writeDeviceOwner();
+                for (int userId : getProfileOwnerKeys()) {
+                    writeProfileOwner(userId);
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "Deleting legacy config file");
+                }
+                if (!legacy.delete()) {
+                    Slog.e(TAG, "Failed to remove the legacy setting file");
+                }
+                return;
+            }
+
+            // No legacy file, read from the new format files.
+            new DeviceOwnerReadWriter().readFromFileLocked();
+
+            final List<UserInfo> users = mUserManager.getUsers();
+            for (UserInfo ui : users) {
+                new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
+            }
+        }
+    }
+
+    String getDeviceOwnerPackageName() {
+        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
+    }
+
+    String getDeviceOwnerName() {
+        return mDeviceOwner != null ? mDeviceOwner.name : null;
+    }
+
+    void setDeviceOwner(String packageName, String ownerName) {
+        mDeviceOwner = new OwnerInfo(ownerName, packageName);
+    }
+
+    void clearDeviceOwner() {
+        mDeviceOwner = null;
+    }
+
+    ComponentName getDeviceInitializerComponent() {
+        return mDeviceInitializer.admin;
+    }
+
+    String getDeviceInitializerPackageName() {
+        return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
+    }
+
+    void setDeviceInitializer(ComponentName admin) {
+        mDeviceInitializer = new OwnerInfo(null, admin);
+    }
+
+    void clearDeviceInitializer() {
+        mDeviceInitializer = null;
+    }
+
+    boolean hasDeviceInitializer() {
+        return mDeviceInitializer != null;
+    }
+
+    void setProfileOwner(ComponentName admin, String ownerName, int userId) {
+        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
+    }
+
+    void removeProfileOwner(int userId) {
+        mProfileOwners.remove(userId);
+    }
+
+    ComponentName getProfileOwnerComponent(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.admin : null;
+    }
+
+    String getProfileOwnerName(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.name : null;
+    }
+
+    String getProfileOwnerPackage(int userId) {
+        OwnerInfo profileOwner = mProfileOwners.get(userId);
+        return profileOwner != null ? profileOwner.packageName : null;
+    }
+
+    Set<Integer> getProfileOwnerKeys() {
+        return mProfileOwners.keySet();
+    }
+
+    SystemUpdatePolicy getSystemUpdatePolicy() {
+        return mSystemUpdatePolicy;
+    }
+
+    void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
+        mSystemUpdatePolicy = systemUpdatePolicy;
+    }
+
+    void clearSystemUpdatePolicy() {
+        mSystemUpdatePolicy = null;
+    }
+
+    boolean hasDeviceOwner() {
+        return mDeviceOwner != null;
+    }
+
+    static boolean isInstalled(String packageName, PackageManager pm) {
+        try {
+            PackageInfo pi;
+            if ((pi = pm.getPackageInfo(packageName, 0)) != null) {
+                if ((pi.applicationInfo.flags) != 0) {
+                    return true;
+                }
+            }
+        } catch (NameNotFoundException nnfe) {
+            Slog.w(TAG, "Device Owner package " + packageName + " not installed.");
+        }
+        return false;
+    }
+
+    static boolean isInstalledForUser(String packageName, int userHandle) {
+        try {
+            PackageInfo pi = (AppGlobals.getPackageManager())
+                    .getPackageInfo(packageName, 0, userHandle);
+            if (pi != null && pi.applicationInfo.flags != 0) {
+                return true;
+            }
+        } catch (RemoteException re) {
+            throw new RuntimeException("Package manager has died", re);
+        }
+
+        return false;
+    }
+
+    private boolean readLegacyOwnerFile(File file) {
+        if (!file.exists()) {
+            // Already migrated or the device has no owners.
+            return false;
+        }
+        try {
+            InputStream input = new AtomicFile(file).openRead();
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(input, StandardCharsets.UTF_8.name());
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT) {
+                if (type!=XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                String tag = parser.getName();
+                if (tag.equals(TAG_DEVICE_OWNER)) {
+                    String name = parser.getAttributeValue(null, ATTR_NAME);
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    mDeviceOwner = new OwnerInfo(name, packageName);
+                } else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
+                    String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    String initializerComponentStr =
+                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+                    ComponentName admin =
+                            ComponentName.unflattenFromString(initializerComponentStr);
+                    if (admin != null) {
+                        mDeviceInitializer = new OwnerInfo(null, admin);
+                    } else {
+                        mDeviceInitializer = new OwnerInfo(null, packageName);
+                        Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
+                                initializerComponentStr);
+                    }
+                } else if (tag.equals(TAG_PROFILE_OWNER)) {
+                    String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+                    String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
+                    String profileOwnerComponentStr =
+                            parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+                    int userId = Integer.parseInt(parser.getAttributeValue(null, ATTR_USERID));
+                    OwnerInfo profileOwnerInfo = null;
+                    if (profileOwnerComponentStr != null) {
+                        ComponentName admin = ComponentName.unflattenFromString(
+                                profileOwnerComponentStr);
+                        if (admin != null) {
+                            profileOwnerInfo = new OwnerInfo(profileOwnerName, admin);
+                        } else {
+                            // This shouldn't happen but switch from package name -> component name
+                            // might have written bad device owner files. b/17652534
+                            Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
+                                    profileOwnerComponentStr);
+                        }
+                    }
+                    if (profileOwnerInfo == null) {
+                        profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
+                    }
+                    mProfileOwners.put(userId, profileOwnerInfo);
+                } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
+                    mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
+                } else {
+                    throw new XmlPullParserException(
+                            "Unexpected tag in device owner file: " + tag);
+                }
+            }
+            input.close();
+        } catch (XmlPullParserException|IOException e) {
+            Slog.e(TAG, "Error parsing device-owner file", e);
+        }
+        return true;
+    }
+
+    void writeDeviceOwner() {
+        synchronized (this) {
+            if (DEBUG) {
+                Log.d(TAG, "Writing to device owner file");
+            }
+            new DeviceOwnerReadWriter().writeToFileLocked();
+        }
+    }
+
+    void writeProfileOwner(int userId) {
+        synchronized (this) {
+            if (DEBUG) {
+                Log.d(TAG, "Writing to profile owner file for user " + userId);
+            }
+            new ProfileOwnerReadWriter(userId).writeToFileLocked();
+        }
+    }
+
+    private abstract static class FileReadWriter {
+        private final File mFile;
+
+        protected FileReadWriter(File file) {
+            mFile = file;
+        }
+
+        abstract boolean shouldWrite();
+
+        void writeToFileLocked() {
+            if (!shouldWrite()) {
+                if (DEBUG) {
+                    Log.d(TAG, "No need to write to " + mFile);
+                }
+                // No contents, remove the file.
+                if (mFile.exists()) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Deleting existing " + mFile);
+                    }
+                    if (!mFile.delete()) {
+                        Slog.e(TAG, "Failed to remove " + mFile.getPath());
+                    }
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "Writing to " + mFile);
+            }
+
+            final AtomicFile f = new AtomicFile(mFile);
+            FileOutputStream outputStream = null;
+            try {
+                outputStream = f.startWrite();
+                final XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(outputStream, StandardCharsets.UTF_8.name());
+
+                // Root tag
+                out.startDocument(null, true);
+                out.startTag(null, TAG_ROOT);
+
+                // Actual content
+                writeInner(out);
+
+                // Close root
+                out.endTag(null, TAG_ROOT);
+                out.endDocument();
+                out.flush();
+
+                // Commit the content.
+                f.finishWrite(outputStream);
+                outputStream = null;
+
+            } catch (IOException e) {
+                Slog.e(TAG, "Exception when writing", e);
+                if (outputStream != null) {
+                    f.failWrite(outputStream);
+                }
+            }
+        }
+
+        void readFromFileLocked() {
+            if (!mFile.exists()) {
+                if (DEBUG) {
+                    Log.d(TAG, "" + mFile + " doesn't exist");
+                }
+                return;
+            }
+            if (DEBUG) {
+                Log.d(TAG, "Reading from " + mFile);
+            }
+            final AtomicFile f = new AtomicFile(mFile);
+            InputStream input = null;
+            try {
+                input = f.openRead();
+                final XmlPullParser parser = Xml.newPullParser();
+                parser.setInput(input, StandardCharsets.UTF_8.name());
+
+                int type;
+                int depth = 0;
+                while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+                    switch (type) {
+                        case XmlPullParser.START_TAG:
+                            depth++;
+                            break;
+                        case XmlPullParser.END_TAG:
+                            depth--;
+                            // fallthrough
+                        default:
+                            continue;
+                    }
+                    // Check the root tag
+                    final String tag = parser.getName();
+                    if (depth == 1) {
+                        if (!TAG_ROOT.equals(tag)) {
+                            Slog.e(TAG, "Invalid root tag: " + tag);
+                            return;
+                        }
+                        continue;
+                    }
+                    // readInner() will only see START_TAG at depth >= 2.
+                    if (!readInner(parser, depth, tag)) {
+                        return; // Error
+                    }
+                }
+            } catch (XmlPullParserException | IOException e) {
+                Slog.e(TAG, "Error parsing device-owner file", e);
+            } finally {
+                IoUtils.closeQuietly(input);
+            }
+        }
+
+        abstract void writeInner(XmlSerializer out) throws IOException;
+
+        abstract boolean readInner(XmlPullParser parser, int depth, String tag);
+
+    }
+
+    private class DeviceOwnerReadWriter extends FileReadWriter {
+
+        protected DeviceOwnerReadWriter() {
+            super(getDeviceOwnerFileWithTestOverride());
+        }
+
+        @Override
+        boolean shouldWrite() {
+            return (mDeviceOwner != null) || (mDeviceInitializer != null)
+                    || (mSystemUpdatePolicy != null);
+        }
+
+        @Override
+        void writeInner(XmlSerializer out) throws IOException {
+            if (mDeviceOwner != null) {
+                mDeviceOwner.writeToXml(out, TAG_DEVICE_OWNER);
+            }
+            if (mDeviceInitializer != null) {
+                mDeviceInitializer.writeToXml(out, TAG_DEVICE_INITIALIZER);
+            }
+            if (mSystemUpdatePolicy != null) {
+                out.startTag(null, TAG_SYSTEM_UPDATE_POLICY);
+                mSystemUpdatePolicy.saveToXml(out);
+                out.endTag(null, TAG_SYSTEM_UPDATE_POLICY);
+            }
+        }
+
+        @Override
+        boolean readInner(XmlPullParser parser, int depth, String tag) {
+            if (depth > 2) {
+                return true; // Ignore
+            }
+            switch (tag) {
+                case TAG_DEVICE_OWNER:
+                    mDeviceOwner = OwnerInfo.readFromXml(parser);
+                    break;
+                case TAG_DEVICE_INITIALIZER:
+                    mDeviceInitializer = OwnerInfo.readFromXml(parser);
+                    break;
+                case TAG_SYSTEM_UPDATE_POLICY:
+                    mSystemUpdatePolicy = SystemUpdatePolicy.restoreFromXml(parser);
+                    break;
+                default:
+                    Slog.e(TAG, "Unexpected tag: " + tag);
+                    return false;
+
+            }
+            return true;
+        }
+    }
+
+    private class ProfileOwnerReadWriter extends FileReadWriter {
+        private final int mUserId;
+
+        ProfileOwnerReadWriter(int userId) {
+            super(getProfileOwnerFileWithTestOverride(userId));
+            mUserId = userId;
+        }
+
+        @Override
+        boolean shouldWrite() {
+            return mProfileOwners.get(mUserId) != null;
+        }
+
+        @Override
+        void writeInner(XmlSerializer out) throws IOException {
+            final OwnerInfo profileOwner = mProfileOwners.get(mUserId);
+            if (profileOwner != null) {
+                profileOwner.writeToXml(out, TAG_PROFILE_OWNER);
+            }
+        }
+
+        @Override
+        boolean readInner(XmlPullParser parser, int depth, String tag) {
+            if (depth > 2) {
+                return true; // Ignore
+            }
+            switch (tag) {
+                case TAG_PROFILE_OWNER:
+                    mProfileOwners.put(mUserId, OwnerInfo.readFromXml(parser));
+                    break;
+                default:
+                    Slog.e(TAG, "Unexpected tag: " + tag);
+                    return false;
+
+            }
+            return true;
+        }
+    }
+
+    private static class OwnerInfo {
+        public final String name;
+        public final String packageName;
+        public final ComponentName admin;
+
+        public OwnerInfo(String name, String packageName) {
+            this.name = name;
+            this.packageName = packageName;
+            this.admin = new ComponentName(packageName, "");
+        }
+
+        public OwnerInfo(String name, ComponentName admin) {
+            this.name = name;
+            this.admin = admin;
+            this.packageName = admin.getPackageName();
+        }
+
+        public void writeToXml(XmlSerializer out, String tag) throws IOException {
+            out.startTag(null, tag);
+            out.attribute(null, ATTR_PACKAGE, packageName);
+            if (name != null) {
+                out.attribute(null, ATTR_NAME, name);
+            }
+            if (admin != null) {
+                out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
+            }
+            out.endTag(null, tag);
+        }
+
+        public static OwnerInfo readFromXml(XmlPullParser parser) {
+            final String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
+            final String name = parser.getAttributeValue(null, ATTR_NAME);
+            final String componentName =
+                    parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
+
+            // Has component name?  If so, return [name, component]
+            if (componentName != null) {
+                final ComponentName admin = ComponentName.unflattenFromString(componentName);
+                if (admin != null) {
+                    return new OwnerInfo(name, admin);
+                } else {
+                    // This shouldn't happen but switch from package name -> component name
+                    // might have written bad device owner files. b/17652534
+                    Slog.e(TAG, "Error parsing device-owner file. Bad component name " +
+                            componentName);
+                }
+            }
+
+            // Else, build with [name, package]
+            return new OwnerInfo(name, packageName);
+        }
+
+        public void dump(String prefix, PrintWriter pw) {
+            pw.println(prefix + "admin=" + admin);
+            pw.println(prefix + "name=" + name);
+            pw.println(prefix + "package=" + packageName);
+            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);
+            }
+        }
+    }
+
+    File getLegacyConfigFileWithTestOverride() {
+        return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML_LEGACY);
+    }
+
+    File getDeviceOwnerFileWithTestOverride() {
+        return new File(Environment.getSystemSecureDirectory(), DEVICE_OWNER_XML);
+    }
+
+    File getProfileOwnerFileWithTestOverride(int userId) {
+        return new File(Environment.getUserSystemDirectory(userId), PROFILE_OWNER_XML);
+    }
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 21dd647b..aafaf83 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -38,6 +38,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.Trace;
 import android.os.UserHandle;
 import android.os.storage.IMountService;
 import android.util.DisplayMetrics;
@@ -175,97 +176,103 @@
     }
 
     private void run() {
-        // If a device's clock is before 1970 (before 0), a lot of
-        // APIs crash dealing with negative numbers, notably
-        // java.io.File#setLastModified, so instead we fake it and
-        // hope that time from cell towers or NTP fixes it shortly.
-        if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
-            Slog.w(TAG, "System clock is before 1970; setting to 1970.");
-            SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
-        }
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitBeforeStartServices");
+            // If a device's clock is before 1970 (before 0), a lot of
+            // APIs crash dealing with negative numbers, notably
+            // java.io.File#setLastModified, so instead we fake it and
+            // hope that time from cell towers or NTP fixes it shortly.
+            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
+                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
+                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
+            }
 
-        // If the system has "persist.sys.language" and friends set, replace them with
-        // "persist.sys.locale". Note that the default locale at this point is calculated
-        // using the "-Duser.locale" command line flag. That flag is usually populated by
-        // AndroidRuntime using the same set of system properties, but only the system_server
-        // and system apps are allowed to set them.
-        //
-        // NOTE: Most changes made here will need an equivalent change to
-        // core/jni/AndroidRuntime.cpp
-        if (!SystemProperties.get("persist.sys.language").isEmpty()) {
-            final String languageTag = Locale.getDefault().toLanguageTag();
+            // If the system has "persist.sys.language" and friends set, replace them with
+            // "persist.sys.locale". Note that the default locale at this point is calculated
+            // using the "-Duser.locale" command line flag. That flag is usually populated by
+            // AndroidRuntime using the same set of system properties, but only the system_server
+            // and system apps are allowed to set them.
+            //
+            // NOTE: Most changes made here will need an equivalent change to
+            // core/jni/AndroidRuntime.cpp
+            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
+                final String languageTag = Locale.getDefault().toLanguageTag();
 
-            SystemProperties.set("persist.sys.locale", languageTag);
-            SystemProperties.set("persist.sys.language", "");
-            SystemProperties.set("persist.sys.country", "");
-            SystemProperties.set("persist.sys.localevar", "");
-        }
+                SystemProperties.set("persist.sys.locale", languageTag);
+                SystemProperties.set("persist.sys.language", "");
+                SystemProperties.set("persist.sys.country", "");
+                SystemProperties.set("persist.sys.localevar", "");
+            }
 
-        // Here we go!
-        Slog.i(TAG, "Entered the Android system server!");
-        EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
+            // Here we go!
+            Slog.i(TAG, "Entered the Android system server!");
+            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
 
-        // In case the runtime switched since last boot (such as when
-        // the old runtime was removed in an OTA), set the system
-        // property so that it is in sync. We can't do this in
-        // libnativehelper's JniInvocation::Init code where we already
-        // had to fallback to a different runtime because it is
-        // running as root and we need to be the system user to set
-        // the property. http://b/11463182
-        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
+            // In case the runtime switched since last boot (such as when
+            // the old runtime was removed in an OTA), set the system
+            // property so that it is in sync. We can't do this in
+            // libnativehelper's JniInvocation::Init code where we already
+            // had to fallback to a different runtime because it is
+            // running as root and we need to be the system user to set
+            // the property. http://b/11463182
+            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
 
-        // Enable the sampling profiler.
-        if (SamplingProfilerIntegration.isEnabled()) {
-            SamplingProfilerIntegration.start();
-            mProfilerSnapshotTimer = new Timer();
-            mProfilerSnapshotTimer.schedule(new TimerTask() {
-                @Override
-                public void run() {
-                    SamplingProfilerIntegration.writeSnapshot("system_server", null);
-                }
-            }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
-        }
+            // Enable the sampling profiler.
+            if (SamplingProfilerIntegration.isEnabled()) {
+                SamplingProfilerIntegration.start();
+                mProfilerSnapshotTimer = new Timer();
+                mProfilerSnapshotTimer.schedule(new TimerTask() {
+                        @Override
+                        public void run() {
+                            SamplingProfilerIntegration.writeSnapshot("system_server", null);
+                        }
+                    }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
+            }
 
-        // Mmmmmm... more memory!
-        VMRuntime.getRuntime().clearGrowthLimit();
+            // Mmmmmm... more memory!
+            VMRuntime.getRuntime().clearGrowthLimit();
 
-        // The system server has to run all of the time, so it needs to be
-        // as efficient as possible with its memory usage.
-        VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
+            // The system server has to run all of the time, so it needs to be
+            // as efficient as possible with its memory usage.
+            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
 
-        // Some devices rely on runtime fingerprint generation, so make sure
-        // we've defined it before booting further.
-        Build.ensureFingerprintProperty();
+            // Some devices rely on runtime fingerprint generation, so make sure
+            // we've defined it before booting further.
+            Build.ensureFingerprintProperty();
 
-        // Within the system server, it is an error to access Environment paths without
-        // explicitly specifying a user.
-        Environment.setUserRequired(true);
+            // Within the system server, it is an error to access Environment paths without
+            // explicitly specifying a user.
+            Environment.setUserRequired(true);
 
-        // Ensure binder calls into the system always run at foreground priority.
-        BinderInternal.disableBackgroundScheduling(true);
+            // Ensure binder calls into the system always run at foreground priority.
+            BinderInternal.disableBackgroundScheduling(true);
 
-        // Prepare the main looper thread (this thread).
-        android.os.Process.setThreadPriority(
+            // Prepare the main looper thread (this thread).
+            android.os.Process.setThreadPriority(
                 android.os.Process.THREAD_PRIORITY_FOREGROUND);
-        android.os.Process.setCanSelfBackground(false);
-        Looper.prepareMainLooper();
+            android.os.Process.setCanSelfBackground(false);
+            Looper.prepareMainLooper();
 
-        // Initialize native services.
-        System.loadLibrary("android_servers");
+            // Initialize native services.
+            System.loadLibrary("android_servers");
 
-        // Check whether we failed to shut down last time we tried.
-        // This call may not return.
-        performPendingShutdown();
+            // Check whether we failed to shut down last time we tried.
+            // This call may not return.
+            performPendingShutdown();
 
-        // Initialize the system context.
-        createSystemContext();
+            // Initialize the system context.
+            createSystemContext();
 
-        // Create the system service manager.
-        mSystemServiceManager = new SystemServiceManager(mSystemContext);
-        LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
+            // Create the system service manager.
+            mSystemServiceManager = new SystemServiceManager(mSystemContext);
+            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+        }
 
         // Start services.
         try {
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartServices");
             startBootstrapServices();
             startCoreServices();
             startOtherServices();
@@ -273,6 +280,8 @@
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting system services", ex);
             throw ex;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
 
         // For debug builds, log event loop stalls to dropbox for analysis.
@@ -340,7 +349,9 @@
 
         // Now that the power manager has been started, let the activity manager
         // initialize power management features.
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "InitPowerManagement");
         mActivityManagerService.initPowerManagement();
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         // Manages LEDs and display backlight so we need it to bring up the display.
         mSystemServiceManager.startService(LightsService.class);
@@ -363,14 +374,16 @@
         }
 
         // Start the package manager.
-        Slog.i(TAG, "Package Manager");
+        traceBeginAndSlog("StartPackageManagerService");
         mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                 mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
         mFirstBoot = mPackageManagerService.isFirstBoot();
         mPackageManager = mSystemContext.getPackageManager();
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-        Slog.i(TAG, "User Service");
+        traceBeginAndSlog("StartUserManagerService");
         ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         // Initialize attribute cache used to cache resources from packages.
         AttributeCache.init(mSystemContext);
@@ -442,17 +455,20 @@
             Slog.i(TAG, "Reading configuration...");
             SystemConfig.getInstance();
 
-            Slog.i(TAG, "Scheduling Policy");
+            traceBeginAndSlog("StartSchedulingPolicyService");
             ServiceManager.addService("scheduling_policy", new SchedulingPolicyService());
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             mSystemServiceManager.startService(TelecomLoaderService.class);
 
-            Slog.i(TAG, "Telephony Registry");
+            traceBeginAndSlog("StartTelephonyRegistry");
             telephonyRegistry = new TelephonyRegistry(context);
             ServiceManager.addService("telephony.registry", telephonyRegistry);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Entropy Mixer");
+            traceBeginAndSlog("StartEntropyMixer");
             entropyMixer = new EntropyMixer(context);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             mContentResolver = context.getContentResolver();
 
@@ -460,47 +476,55 @@
             mSystemServiceManager.startService(CameraService.class);
 
             // The AccountManager must come before the ContentService
+            traceBeginAndSlog("StartAccountManagerService");
             try {
                 // TODO: seems like this should be disable-able, but req'd by ContentService
-                Slog.i(TAG, "Account Manager");
                 accountManager = new AccountManagerService(context);
                 ServiceManager.addService(Context.ACCOUNT_SERVICE, accountManager);
             } catch (Throwable e) {
                 Slog.e(TAG, "Failure starting Account Manager", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Content Manager");
+            traceBeginAndSlog("StartContentService");
             contentService = ContentService.main(context,
                     mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "System Content Providers");
+            traceBeginAndSlog("InstallSystemProviders");
             mActivityManagerService.installSystemProviders();
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Vibrator Service");
+            traceBeginAndSlog("StartVibratorService");
             vibrator = new VibratorService(context);
             ServiceManager.addService("vibrator", vibrator);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Consumer IR Service");
+            traceBeginAndSlog("StartConsumerIrService");
             consumerIr = new ConsumerIrService(context);
             ServiceManager.addService(Context.CONSUMER_IR_SERVICE, consumerIr);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             mSystemServiceManager.startService(AlarmManagerService.class);
             alarm = IAlarmManager.Stub.asInterface(
                     ServiceManager.getService(Context.ALARM_SERVICE));
 
-            Slog.i(TAG, "Init Watchdog");
+            traceBeginAndSlog("InitWatchdog");
             final Watchdog watchdog = Watchdog.getInstance();
             watchdog.init(context, mActivityManagerService);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Input Manager");
+            traceBeginAndSlog("StartInputManagerService");
             inputManager = new InputManagerService(context);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
-            Slog.i(TAG, "Window Manager");
+            traceBeginAndSlog("StartWindowManagerService");
             wm = WindowManagerService.main(context, inputManager,
                     mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                     !mFirstBoot, mOnlyCore);
             ServiceManager.addService(Context.WINDOW_SERVICE, wm);
             ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             mActivityManagerService.setWindowManager(wm);
 
@@ -523,7 +547,6 @@
             } else if (disableBluetooth) {
                 Slog.i(TAG, "Bluetooth Service disabled by config");
             } else {
-                Slog.i(TAG, "Bluetooth Service");
                 mSystemServiceManager.startService(BluetoothService.class);
             }
         } catch (RuntimeException e) {
@@ -544,21 +567,23 @@
 
         // Bring up services needed for UI.
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
+            traceBeginAndSlog("StartInputMethodManagerService");
             try {
-                Slog.i(TAG, "Input Method Service");
                 imm = new InputMethodManagerService(context);
                 ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
             } catch (Throwable e) {
                 reportWtf("starting Input Manager Service", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+            traceBeginAndSlog("StartAccessibilityManagerService");
             try {
-                Slog.i(TAG, "Accessibility Manager");
                 ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,
                         new AccessibilityManagerService(context));
             } catch (Throwable e) {
                 reportWtf("starting Accessibility Manager", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         }
 
         try {
@@ -588,11 +613,13 @@
         // as appropriate.
         mSystemServiceManager.startService(UiModeManagerService.class);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PerformBootDexOpt");
         try {
             mPackageManagerService.performBootDexOpt();
         } catch (Throwable e) {
             reportWtf("performing boot dexopt", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         try {
             ActivityManagerNative.getDefault().showBootMessage(
@@ -604,13 +631,14 @@
 
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartLockSettingsService");
                 try {
-                    Slog.i(TAG,  "LockSettingsService");
                     lockSettings = new LockSettingsService(context);
                     ServiceManager.addService("lock_settings", lockSettings);
                 } catch (Throwable e) {
                     reportWtf("starting LockSettingsService service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 if (!SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("")) {
                     mSystemServiceManager.startService(PersistentDataBlockService.class);
@@ -624,64 +652,70 @@
             }
 
             if (!disableSystemUI) {
+                traceBeginAndSlog("StartStatusBarManagerService");
                 try {
-                    Slog.i(TAG, "Status Bar");
                     statusBar = new StatusBarManagerService(context, wm);
                     ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
                 } catch (Throwable e) {
                     reportWtf("starting StatusBarManagerService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartClipboardService");
                 try {
-                    Slog.i(TAG, "Clipboard Service");
                     ServiceManager.addService(Context.CLIPBOARD_SERVICE,
                             new ClipboardService(context));
                 } catch (Throwable e) {
                     reportWtf("starting Clipboard Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNetwork) {
+                traceBeginAndSlog("StartNetworkManagementService");
                 try {
-                    Slog.i(TAG, "NetworkManagement Service");
                     networkManagement = NetworkManagementService.create(context);
                     ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkManagement Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartTextServicesManagerService");
                 try {
-                    Slog.i(TAG, "Text Service Manager Service");
                     tsms = new TextServicesManagerService(context);
                     ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms);
                 } catch (Throwable e) {
                     reportWtf("starting Text Service Manager Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNetwork) {
+                traceBeginAndSlog("StartNetworkScoreService");
                 try {
-                    Slog.i(TAG, "Network Score Service");
                     networkScore = new NetworkScoreService(context);
                     ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
                 } catch (Throwable e) {
                     reportWtf("starting Network Score Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                traceBeginAndSlog("StartNetworkStatsService");
                 try {
-                    Slog.i(TAG, "NetworkStats Service");
                     networkStats = new NetworkStatsService(context, networkManagement, alarm);
                     ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkStats Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                traceBeginAndSlog("StartNetworkPolicyManagerService");
                 try {
-                    Slog.i(TAG, "NetworkPolicy Service");
                     networkPolicy = new NetworkPolicyManagerService(
                             context, mActivityManagerService,
                             (IPowerManager)ServiceManager.getService(Context.POWER_SERVICE),
@@ -690,6 +724,7 @@
                 } catch (Throwable e) {
                     reportWtf("starting NetworkPolicy Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
                 mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
@@ -703,8 +738,8 @@
                     mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
                 }
 
+                traceBeginAndSlog("StartConnectivityService");
                 try {
-                    Slog.i(TAG, "Connectivity Service");
                     connectivity = new ConnectivityService(
                             context, networkManagement, networkStats, networkPolicy);
                     ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity);
@@ -713,25 +748,28 @@
                 } catch (Throwable e) {
                     reportWtf("starting Connectivity Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                traceBeginAndSlog("StartNsdService");
                 try {
-                    Slog.i(TAG, "Network Service Discovery Service");
                     serviceDiscovery = NsdService.create(context);
                     ServiceManager.addService(
                             Context.NSD_SERVICE, serviceDiscovery);
                 } catch (Throwable e) {
                     reportWtf("starting Service Discovery Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartUpdateLockService");
                 try {
-                    Slog.i(TAG, "UpdateLock Service");
                     ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
                             new UpdateLockService(context));
                 } catch (Throwable e) {
                     reportWtf("starting UpdateLockService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             /*
@@ -740,25 +778,31 @@
              * first before continuing.
              */
             if (mountService != null && !mOnlyCore) {
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WaitForAsecScan");
                 try {
                     mountService.waitForAsecScan();
                 } catch (RemoteException ignored) {
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAccountManagerServiceReady");
             try {
                 if (accountManager != null)
                     accountManager.systemReady();
             } catch (Throwable e) {
                 reportWtf("making Account Manager Service ready", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+            Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeContentServiceReady");
             try {
                 if (contentService != null)
                     contentService.systemReady();
             } catch (Throwable e) {
                 reportWtf("making Content Service ready", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             mSystemServiceManager.startService(NotificationManagerService.class);
             notification = INotificationManager.Stub.asInterface(
@@ -768,66 +812,72 @@
             mSystemServiceManager.startService(DeviceStorageMonitorService.class);
 
             if (!disableLocation) {
+                traceBeginAndSlog("StartLocationManagerService");
                 try {
-                    Slog.i(TAG, "Location Manager");
                     location = new LocationManagerService(context);
                     ServiceManager.addService(Context.LOCATION_SERVICE, location);
                 } catch (Throwable e) {
                     reportWtf("starting Location Manager", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                traceBeginAndSlog("StartCountryDetectorService");
                 try {
-                    Slog.i(TAG, "Country Detector");
                     countryDetector = new CountryDetectorService(context);
                     ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
                 } catch (Throwable e) {
                     reportWtf("starting Country Detector", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartSearchManagerService");
                 try {
-                    Slog.i(TAG, "Search Service");
                     ServiceManager.addService(Context.SEARCH_SERVICE,
                             new SearchManagerService(context));
                 } catch (Throwable e) {
                     reportWtf("starting Search Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             mSystemServiceManager.startService(DropBoxManagerService.class);
 
             if (!disableNonCoreServices && context.getResources().getBoolean(
                         R.bool.config_enableWallpaperService)) {
+                traceBeginAndSlog("StartWallpaperManagerService");
                 try {
-                    Slog.i(TAG, "Wallpaper Service");
                     wallpaper = new WallpaperManagerService(context);
                     ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);
                 } catch (Throwable e) {
                     reportWtf("starting Wallpaper Service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
+            traceBeginAndSlog("StartAudioService");
             try {
-                Slog.i(TAG, "Audio Service");
                 audioService = new AudioService(context);
                 ServiceManager.addService(Context.AUDIO_SERVICE, audioService);
             } catch (Throwable e) {
                 reportWtf("starting Audio Service", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNonCoreServices) {
                 mSystemServiceManager.startService(DockObserver.class);
             }
 
+            traceBeginAndSlog("StartWiredAccessoryManager");
             try {
-                Slog.i(TAG, "Wired Accessory Manager");
                 // Listen for wired headset changes
                 inputManager.setWiredAccessoryCallbacks(
                         new WiredAccessoryManager(context, inputManager));
             } catch (Throwable e) {
                 reportWtf("starting WiredAccessoryManager", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNonCoreServices) {
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
@@ -839,17 +889,20 @@
                         || mPackageManager.hasSystemFeature(
                                 PackageManager.FEATURE_USB_ACCESSORY)) {
                     // Manage USB host and device support
+                    Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartUsbService");
                     mSystemServiceManager.startService(USB_SERVICE_CLASS);
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                 }
 
+                traceBeginAndSlog("StartSerialService");
                 try {
-                    Slog.i(TAG, "Serial Service");
                     // Serial port support
                     serial = new SerialService(context);
                     ServiceManager.addService(Context.SERIAL_SERVICE, serial);
                 } catch (Throwable e) {
                     Slog.e(TAG, "Failure starting SerialService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             mSystemServiceManager.startService(TwilightService.class);
@@ -875,49 +928,54 @@
                 }
             }
 
+            traceBeginAndSlog("StartDiskStatsService");
             try {
-                Slog.i(TAG, "DiskStats Service");
                 ServiceManager.addService("diskstats", new DiskStatsService(context));
             } catch (Throwable e) {
                 reportWtf("starting DiskStats Service", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+            traceBeginAndSlog("StartSamplingProfilerService");
             try {
                 // need to add this service even if SamplingProfilerIntegration.isEnabled()
                 // is false, because it is this service that detects system property change and
                 // turns on SamplingProfilerIntegration. Plus, when sampling profiler doesn't work,
                 // there is little overhead for running this service.
-                Slog.i(TAG, "SamplingProfiler Service");
                 ServiceManager.addService("samplingprofiler",
                             new SamplingProfilerService(context));
             } catch (Throwable e) {
                 reportWtf("starting SamplingProfiler Service", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNetwork && !disableNetworkTime) {
+                traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
-                    Slog.i(TAG, "NetworkTimeUpdateService");
                     networkTimeUpdater = new NetworkTimeUpdateService(context);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkTimeUpdate service", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
+            traceBeginAndSlog("StartCommonTimeManagementService");
             try {
-                Slog.i(TAG, "CommonTimeManagementService");
                 commonTimeMgmtService = new CommonTimeManagementService(context);
                 ServiceManager.addService("commontime_management", commonTimeMgmtService);
             } catch (Throwable e) {
                 reportWtf("starting CommonTimeManagementService service", e);
             }
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             if (!disableNetwork) {
+                traceBeginAndSlog("CertBlacklister");
                 try {
-                    Slog.i(TAG, "CertBlacklister");
                     CertBlacklister blacklister = new CertBlacklister(context);
                 } catch (Throwable e) {
                     reportWtf("starting CertBlacklister", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
@@ -926,13 +984,14 @@
             }
 
             if (!disableNonCoreServices && ZygoteInit.PRELOAD_RESOURCES) {
+                traceBeginAndSlog("StartAssetAtlasService");
                 try {
-                    Slog.i(TAG, "Assets Atlas Service");
                     atlas = new AssetAtlasService(context);
                     ServiceManager.addService(AssetAtlasService.ASSET_ATLAS_SERVICE, atlas);
                 } catch (Throwable e) {
                     reportWtf("starting AssetAtlasService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
 
             if (!disableNonCoreServices) {
@@ -957,24 +1016,26 @@
             }
 
             if (!disableNonCoreServices) {
+                traceBeginAndSlog("StartMediaRouterService");
                 try {
-                    Slog.i(TAG, "Media Router Service");
                     mediaRouter = new MediaRouterService(context);
                     ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
                 } catch (Throwable e) {
                     reportWtf("starting MediaRouterService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 mSystemServiceManager.startService(TrustManagerService.class);
 
                 mSystemServiceManager.startService(FingerprintService.class);
 
+                traceBeginAndSlog("StartBackgroundDexOptService");
                 try {
-                    Slog.i(TAG, "BackgroundDexOptService");
                     BackgroundDexOptService.schedule(context, 0);
                 } catch (Throwable e) {
                     reportWtf("starting BackgroundDexOptService", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
             }
 
@@ -1002,12 +1063,15 @@
 
         // It is now time to start up the app processes...
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeVibratorServiceReady");
         try {
             vibrator.systemReady();
         } catch (Throwable e) {
             reportWtf("making Vibrator Service ready", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeLockSettingsServiceReady");
         if (lockSettings != null) {
             try {
                 lockSettings.systemReady();
@@ -1015,17 +1079,20 @@
                 reportWtf("making Lock Settings Service ready", e);
             }
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         // Needed by DevicePolicyManager for initialization
         mSystemServiceManager.startBootPhase(SystemService.PHASE_LOCK_SETTINGS_READY);
 
         mSystemServiceManager.startBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeWindowManagerServiceReady");
         try {
             wm.systemReady();
         } catch (Throwable e) {
             reportWtf("making Window Manager Service ready", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         if (safeMode) {
             mActivityManagerService.showSafeModeOverlay();
@@ -1046,25 +1113,32 @@
             systemTheme.rebase();
         }
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePowerManagerServiceReady");
         try {
             // TODO: use boot phase
             mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         } catch (Throwable e) {
             reportWtf("making Power Manager Service ready", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakePackageManagerServiceReady");
         try {
             mPackageManagerService.systemReady();
         } catch (Throwable e) {
             reportWtf("making Package Manager Service ready", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeDisplayManagerServiceReady");
         try {
             // TODO: use boot phase and communicate these flags some other way
             mDisplayManagerService.systemReady(safeMode, mOnlyCore);
         } catch (Throwable e) {
             reportWtf("making Display Manager Service ready", e);
         }
+        Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
         // These are needed to propagate to the runnable below.
         final NetworkManagementService networkManagementF = networkManagement;
@@ -1098,55 +1172,76 @@
                 Slog.i(TAG, "Making services ready");
                 mSystemServiceManager.startBootPhase(
                         SystemService.PHASE_ACTIVITY_MANAGER_READY);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseActivityManagerReady");
 
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartObservingNativeCrashes");
                 try {
                     mActivityManagerService.startObservingNativeCrashes();
                 } catch (Throwable e) {
                     reportWtf("observing native crashes", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
                 Slog.i(TAG, "WebViewFactory preparation");
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "WebViewFactoryPreparation");
                 WebViewFactory.prepareWebViewInSystemServer();
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "StartSystemUI");
                 try {
                     startSystemUi(context);
                 } catch (Throwable e) {
                     reportWtf("starting System UI", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeMountServiceReady");
                 try {
                     if (networkScoreF != null) networkScoreF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Score Service ready", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkManagementServiceReady");
                 try {
                     if (networkManagementF != null) networkManagementF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Managment Service ready", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkStatsServiceReady");
                 try {
                     if (networkStatsF != null) networkStatsF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Stats Service ready", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeNetworkPolicyServiceReady");
                 try {
                     if (networkPolicyF != null) networkPolicyF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Network Policy Service ready", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeConnectivityServiceReady");
                 try {
                     if (connectivityF != null) connectivityF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Connectivity Service ready", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "MakeAudioServiceReady");
                 try {
                     if (audioServiceF != null) audioServiceF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("Notifying AudioService running", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
                 Watchdog.getInstance().start();
 
                 // It is now okay to let the various system services start their
                 // third party code...
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, "PhaseThirdPartyAppsCanStart");
                 mSystemServiceManager.startBootPhase(
                         SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
 
@@ -1215,6 +1310,7 @@
                 } catch (Throwable e) {
                     reportWtf("Notifying MmsService running", e);
                 }
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
             }
         });
     }
@@ -1226,4 +1322,9 @@
         //Slog.d(TAG, "Starting service: " + intent);
         context.startServiceAsUser(intent, UserHandle.SYSTEM);
     }
+
+    private static void traceBeginAndSlog(String name) {
+        Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+        Slog.i(TAG, name);
+    }
 }
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a91ddb8..cbf8fc2 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -55,6 +55,7 @@
     public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
     public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
 
+    public static final int HWADDR_LEN = 16;
     public static final int MAX_OPTION_LEN = 255;
     /**
      * IP layer definitions.
@@ -399,7 +400,7 @@
         buf.put(mRelayIp.getAddress());
         buf.put(mClientMac);
         buf.position(buf.position() +
-                     (16 - mClientMac.length) // pad addr to 16 bytes
+                     (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes
                      + 64     // empty server host name (64 bytes)
                      + 128);  // empty boot file name (128 bytes)
         buf.putInt(0x63825363); // magic number
@@ -786,7 +787,7 @@
 
         byte type = packet.get();
         byte hwType = packet.get();
-        byte addrLen = packet.get();
+        int addrLen = packet.get() & 0xff;
         byte hops = packet.get();
         transactionId = packet.getInt();
         secs = packet.getShort();
@@ -807,6 +808,16 @@
             return null;
         }
 
+        // Some DHCP servers have been known to announce invalid client hardware address values such
+        // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
+        // all but only checks that the interface MAC address matches the first bytes of the address
+        // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
+        // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
+        // TODO: evaluate whether to make this test more liberal.
+        if (addrLen > HWADDR_LEN) {
+            addrLen = ETHER_BROADCAST.length;
+        }
+
         clientMac = new byte[addrLen];
         packet.get(clientMac);
 
diff --git a/services/tests/servicestests/assets/OwnersTest/test01/input.xml b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
new file mode 100644
index 0000000..db3e974
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test01/input.xml
@@ -0,0 +1 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
diff --git a/services/tests/servicestests/assets/OwnersTest/test02/input.xml b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
new file mode 100644
index 0000000..321842b
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test02/input.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.google.android.testdpc" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test03/input.xml b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
new file mode 100644
index 0000000..1bbfdadf
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test03/input.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
+<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test04/input.xml b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
new file mode 100644
index 0000000..8be51d9
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test04/input.xml
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.google.android.testdpc" />
+<profile-owner package="com.google.android.testdpc0" name="0" userId="10" component="com.google.android.testdpc/com.google.android.testdpc.DeviceAdminReceiver0" />
+<profile-owner package="com.google.android.testdpc1" name="1" userId="11" />
+<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
+<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/assets/OwnersTest/test05/input.xml b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
new file mode 100644
index 0000000..dbcb858
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test05/input.xml
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-initializer package="com.google.android.testdpcx" name="di" component="com.google.android.testdpcx/receiver" />
+
diff --git a/services/tests/servicestests/assets/OwnersTest/test06/input.xml b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
new file mode 100644
index 0000000..794622b
--- /dev/null
+++ b/services/tests/servicestests/assets/OwnersTest/test06/input.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<system-update-policy policy_type="5" />
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index da1df1a..cd3b8bb 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -333,6 +333,76 @@
     }
 
     @SmallTest
+    public void testBadHwaddrLength() throws Exception {
+        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options
+            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
+        ).toCharArray(), false));
+        String expectedClientMac = "30766FF2A90C";
+
+        final int hwAddrLenOffset = 20 + 8 + 2;
+        assertEquals(6, packet.get(hwAddrLenOffset));
+
+        // Expect the expected.
+        DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertNotNull(offerPacket);
+        assertEquals(6, offerPacket.getClientMac().length);
+        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+
+        // Reduce the hardware address length and verify that it shortens the client MAC.
+        packet.flip();
+        packet.put(hwAddrLenOffset, (byte) 5);
+        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertNotNull(offerPacket);
+        assertEquals(5, offerPacket.getClientMac().length);
+        assertEquals(expectedClientMac.substring(0, 10),
+                HexDump.toHexString(offerPacket.getClientMac()));
+
+        packet.flip();
+        packet.put(hwAddrLenOffset, (byte) 3);
+        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertNotNull(offerPacket);
+        assertEquals(3, offerPacket.getClientMac().length);
+        assertEquals(expectedClientMac.substring(0, 6),
+                HexDump.toHexString(offerPacket.getClientMac()));
+
+        // Set the the hardware address length to 0xff and verify that we a) don't treat it as -1
+        // and crash, and b) hardcode it to 6.
+        packet.flip();
+        packet.put(hwAddrLenOffset, (byte) -1);
+        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertNotNull(offerPacket);
+        assertEquals(6, offerPacket.getClientMac().length);
+        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+
+        // Set the the hardware address length to a positive invalid value (> 16) and verify that we
+        // hardcode it to 6.
+        packet.flip();
+        packet.put(hwAddrLenOffset, (byte) 17);
+        offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
+        assertNotNull(offerPacket);
+        assertEquals(6, offerPacket.getClientMac().length);
+        assertEquals(expectedClientMac, HexDump.toHexString(offerPacket.getClientMac()));
+    }
+
+    @SmallTest
     public void testPadAndOverloadedOptionsOffer() throws Exception {
         // A packet observed in the real world that is interesting for two reasons:
         //
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
index fd9fc98..51e14d3 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerServiceTest.java
@@ -54,7 +54,7 @@
      * Timeout in which we are waiting for the system to start the mock
      * accessibility services.
      */
-    private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 300;
+    private static final long TIMEOUT_START_MOCK_ACCESSIBILITY_SERVICES = 1000;
 
     /**
      * Timeout used for testing that a service is notified only upon a
@@ -68,6 +68,12 @@
     private IAccessibilityManager mManagerService;
 
     @Override
+    protected void setUp() throws Exception {
+        // Reset the state.
+        ensureOnlyMockServicesEnabled(getContext(), false, false);
+    }
+
+    @Override
     public void setContext(Context context) {
         super.setContext(context);
         if (MyFirstMockAccessibilityService.sComponentName == null) {
@@ -92,6 +98,9 @@
 
     @LargeTest
     public void testAddClient_AccessibilityDisabledThenEnabled() throws Exception {
+        // at least some service must be enabled, otherwise accessibility will always be disabled.
+        ensureOnlyMockServicesEnabled(mContext, true, false);
+
         // make sure accessibility is disabled
         ensureAccessibilityEnabled(mContext, false);
 
@@ -99,7 +108,8 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        final int stateFlagsDisabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
+        final int stateFlagsDisabled =
+                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
         boolean enabledAccessibilityDisabled =
             (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -111,11 +121,11 @@
         ensureAccessibilityEnabled(mContext, true);
 
         // invoke the method under test
-        final int stateFlagsEnabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
+        final int stateFlagsEnabled =
+                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
         boolean enabledAccessibilityEnabled =
             (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
-
         // check expected result
         assertTrue("The client must be enabled since accessibility is enabled.",
                 enabledAccessibilityEnabled);
@@ -123,6 +133,9 @@
 
     @LargeTest
     public void testAddClient_AccessibilityEnabledThenDisabled() throws Exception {
+        // at least some service must be enabled, otherwise accessibility will always be disabled.
+        ensureOnlyMockServicesEnabled(mContext, true, false);
+
         // enable accessibility before registering the client
         ensureAccessibilityEnabled(mContext, true);
 
@@ -130,7 +143,8 @@
         MyMockAccessibilityManagerClient mockClient = new MyMockAccessibilityManagerClient();
 
         // invoke the method under test
-        final int stateFlagsEnabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
+        final int stateFlagsEnabled =
+                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
         boolean enabledAccessibilityEnabled =
             (stateFlagsEnabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -142,7 +156,8 @@
         ensureAccessibilityEnabled(mContext, false);
 
         // invoke the method under test
-        final int stateFlagsDisabled = mManagerService.addClient(mockClient, UserHandle.USER_OWNER);
+        final int stateFlagsDisabled =
+                mManagerService.addClient(mockClient, UserHandle.USER_CURRENT);
         boolean enabledAccessibilityDisabled =
             (stateFlagsDisabled & AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED) != 0;
 
@@ -162,7 +177,7 @@
 
         // look for the two mock services
         for (AccessibilityServiceInfo info : mManagerService.getInstalledAccessibilityServiceList(
-                UserHandle.USER_OWNER)) {
+                UserHandle.USER_CURRENT)) {
             ServiceInfo serviceInfo = info.getResolveInfo().serviceInfo;
             if (packageName.equals(serviceInfo.packageName)) {
                 if (firstMockServiceClassName.equals(serviceInfo.name)) {
@@ -181,12 +196,12 @@
     @LargeTest
     public void testSendAccessibilityEvent_OneService_MatchingPackageAndEventType()
             throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility service
         ensureOnlyMockServicesEnabled(mContext, true, false);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the mock service
         MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
         service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
@@ -203,7 +218,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -211,12 +226,12 @@
 
     @LargeTest
     public void testSendAccessibilityEvent_OneService_NotMatchingPackage() throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility service
         ensureOnlyMockServicesEnabled(mContext, true, false);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the mock service
         MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
         service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
@@ -233,7 +248,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -241,12 +256,12 @@
 
     @LargeTest
     public void testSendAccessibilityEvent_OneService_NotMatchingEventType() throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility service
         ensureOnlyMockServicesEnabled(mContext, true, false);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the mock service
         MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
         service.setServiceInfo(MockAccessibilityService.createDefaultInfo());
@@ -263,7 +278,7 @@
         service.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(service);
@@ -271,12 +286,12 @@
 
     @LargeTest
     public void testSendAccessibilityEvent_OneService_NotifivationAfterTimeout() throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility service
         ensureOnlyMockServicesEnabled(mContext, true, false);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the mock service
         MockAccessibilityService service = MyFirstMockAccessibilityService.sInstance;
         AccessibilityServiceInfo info = MockAccessibilityService.createDefaultInfo();
@@ -299,8 +314,8 @@
         service.replay();
 
         // send the events
-        mManagerService.sendAccessibilityEvent(firstEvent, UserHandle.USER_OWNER);
-        mManagerService.sendAccessibilityEvent(secondEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(firstEvent, UserHandle.USER_CURRENT);
+        mManagerService.sendAccessibilityEvent(secondEvent, UserHandle.USER_CURRENT);
 
         // wait for #sendAccessibilityEvent to reach the backing service
         Thread.sleep(TIMEOUT_BINDER_CALL);
@@ -322,12 +337,12 @@
     @LargeTest
     public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_DiffFeedback()
             throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility services
         ensureOnlyMockServicesEnabled(mContext, true, true);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the first mock service
         MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
         AccessibilityServiceInfo firstInfo = MockAccessibilityService.createDefaultInfo();
@@ -356,7 +371,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -366,12 +381,12 @@
     @LargeTest
     public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType()
             throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility services
         ensureOnlyMockServicesEnabled(mContext, true, true);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the first mock service
         MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
         firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
@@ -395,7 +410,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -405,12 +420,12 @@
     @LargeTest
     public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_OneDefault()
             throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility services
         ensureOnlyMockServicesEnabled(mContext, true, true);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the first mock service
         MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
         AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
@@ -436,7 +451,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -446,12 +461,12 @@
     @LargeTest
     public void testSendAccessibilityEvent_TwoServices_MatchingPackageAndEventType_TwoDefault()
             throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility services
         ensureOnlyMockServicesEnabled(mContext, true, true);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the first mock service
         MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
         AccessibilityServiceInfo firstInfo = MyFirstMockAccessibilityService.createDefaultInfo();
@@ -479,7 +494,7 @@
         secondService.replay();
 
         // send the event
-        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_OWNER);
+        mManagerService.sendAccessibilityEvent(sentEvent, UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -488,12 +503,12 @@
 
     @LargeTest
     public void testInterrupt() throws Exception {
-        // set the accessibility setting value
-        ensureAccessibilityEnabled(mContext, true);
-
         // enable the mock accessibility services
         ensureOnlyMockServicesEnabled(mContext, true, true);
 
+        // set the accessibility setting value
+        ensureAccessibilityEnabled(mContext, true);
+
         // configure the first mock service
         MockAccessibilityService firstService = MyFirstMockAccessibilityService.sInstance;
         firstService.setServiceInfo(MockAccessibilityService.createDefaultInfo());
@@ -514,7 +529,7 @@
         secondService.replay();
 
         // call the method under test
-        mManagerService.interrupt(UserHandle.USER_OWNER);
+        mManagerService.interrupt(UserHandle.USER_CURRENT);
 
         // verify if all expected methods have been called
         assertMockServiceVerifiedWithinTimeout(firstService);
@@ -534,7 +549,7 @@
         sentEvent.setContentDescription("ContentDescription");
         sentEvent.setCurrentItemIndex(1);
         sentEvent.setEnabled(true);
-        sentEvent.setEventType(AccessibilityEvent.TYPE_VIEW_CLICKED);
+        sentEvent.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
         sentEvent.setEventTime(1000);
         sentEvent.setFromIndex(1);
         sentEvent.setFullScreen(true);
@@ -568,8 +583,8 @@
      * @throws Exception If any error occurs.
      */
     private void ensureAccessibilityEnabled(Context context, boolean enabled) throws Exception {
-        boolean isEnabled = (Settings.Secure.getInt(context.getContentResolver(),
-                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1 ? true : false);
+        boolean isEnabled = Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
 
         if (isEnabled == enabled) {
             return;
@@ -608,13 +623,14 @@
             servicesToEnable.append(MySecondMockAccessibilityService.sComponentName).append(":");
         }
 
+        Settings.Secure.putString(context.getContentResolver(),
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
+
+        // Optimization. If things will not change, we don't have to do anything.
         if (servicesToEnable.equals(enabledServices)) {
             return;
         }
 
-        Settings.Secure.putString(context.getContentResolver(),
-                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, servicesToEnable.toString());
-
         // we have enabled the services of interest and need to wait until they
         // are instantiated and started (if needed) and the system binds to them
         boolean firstMockServiceOK = false;
@@ -664,13 +680,13 @@
             throws Exception {
         Exception lastVerifyException = null;
         long beginTime = SystemClock.uptimeMillis();
-        long pollTmeout = TIMEOUT_BINDER_CALL / 5;
+        long pollTimeout = TIMEOUT_BINDER_CALL / 5;
 
         // poll until the timeout has elapsed
         while (SystemClock.uptimeMillis() - beginTime < TIMEOUT_BINDER_CALL) {
             // sleep first since immediate call will always fail
             try {
-                Thread.sleep(pollTmeout);
+                Thread.sleep(pollTimeout);
             } catch (InterruptedException ie) {
                 /* ignore */
             }
diff --git a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
index e7366ea..026a2ad 100644
--- a/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AccessibilityManagerTest.java
@@ -16,14 +16,11 @@
 
 package com.android.server;
 
-import static org.easymock.EasyMock.createStrictMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.replay;
-import static org.easymock.EasyMock.reportMatcher;
-import static org.easymock.EasyMock.reset;
-import static org.easymock.EasyMock.verify;
-
-import org.easymock.IArgumentMatcher;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.os.UserHandle;
@@ -35,6 +32,9 @@
 import android.view.accessibility.IAccessibilityManager;
 import android.view.accessibility.IAccessibilityManagerClient;
 
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.util.ArrayList;
 import java.util.List;
 
@@ -49,78 +49,65 @@
      */
     public static final long TIMEOUT_BINDER_CALL = 50;
 
-    /**
-     * The reusable mock {@link IAccessibilityManager}.
-     */
-    private final IAccessibilityManager mMockServiceInterface =
-        createStrictMock(IAccessibilityManager.class);
+    @Mock
+    private IAccessibilityManager mMockService;
 
     @Override
     public void setUp() throws Exception {
-        reset(mMockServiceInterface);
+        MockitoAnnotations.initMocks(this);
+    }
+
+    private AccessibilityManager createManager(boolean enabled) throws Exception {
+        if (enabled) {
+            when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
+                    .thenReturn(AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
+        } else {
+            when(mMockService.addClient(any(IAccessibilityManagerClient.class), anyInt()))
+                    .thenReturn(0);
+        }
+
+        AccessibilityManager manager =
+                new AccessibilityManager(mContext, mMockService, UserHandle.USER_CURRENT);
+
+        verify(mMockService).addClient(any(IAccessibilityManagerClient.class), anyInt());
+
+        return manager;
     }
 
     @MediumTest
     public void testGetAccessibilityServiceList() throws Exception {
         // create a list of installed accessibility services the mock service returns
-        List<AccessibilityServiceInfo> expectedServices = new ArrayList<AccessibilityServiceInfo>();
+        List<AccessibilityServiceInfo> expectedServices = new ArrayList<>();
         AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo();
         accessibilityServiceInfo.packageNames = new String[] { "foo.bar" };
         expectedServices.add(accessibilityServiceInfo);
 
         // configure the mock service behavior
-        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
-                UserHandle.USER_OWNER)).andReturn(
-                AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        expect(mockServiceInterface.getInstalledAccessibilityServiceList(UserHandle.USER_OWNER))
-                .andReturn(expectedServices);
-        replay(mockServiceInterface);
+        when(mMockService.getInstalledAccessibilityServiceList(anyInt()))
+                .thenReturn(expectedServices);
 
         // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
-                UserHandle.USER_OWNER);
+        AccessibilityManager manager = createManager(true);
         List<AccessibilityServiceInfo> receivedServices =
-            manager.getInstalledAccessibilityServiceList();
+                manager.getInstalledAccessibilityServiceList();
 
+        verify(mMockService).getInstalledAccessibilityServiceList(UserHandle.USER_CURRENT);
         // check expected result (list equals() compares it contents as well)
-        assertEquals("All expected services must be returned", receivedServices, expectedServices);
-
-        // verify the mock service was properly called
-        verify(mockServiceInterface);
+        assertEquals("All expected services must be returned", expectedServices, receivedServices);
     }
 
     @MediumTest
     public void testInterrupt() throws Exception {
-        // configure the mock service behavior
-        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
-                UserHandle.USER_OWNER)).andReturn(
-                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        mockServiceInterface.interrupt(UserHandle.USER_OWNER);
-        replay(mockServiceInterface);
-
-        // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
-                UserHandle.USER_OWNER);
+        AccessibilityManager manager = createManager(true);
         manager.interrupt();
 
-        // verify the mock service was properly called
-        verify(mockServiceInterface);
+        verify(mMockService).interrupt(UserHandle.USER_CURRENT);
     }
 
     @LargeTest
     public void testIsEnabled() throws Exception {
-        // configure the mock service behavior
-        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
-                UserHandle.USER_OWNER)).andReturn(
-                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        replay(mockServiceInterface);
-
         // invoke the method under test
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
-                UserHandle.USER_OWNER);
+        AccessibilityManager manager = createManager(true);
         boolean isEnabledServiceEnabled = manager.isEnabled();
 
         // check expected result
@@ -138,63 +125,32 @@
         // check expected result
         assertFalse("Must be disabled since the mock service is disabled",
                 isEnabledServcieDisabled);
-
-        // verify the mock service was properly called
-        verify(mockServiceInterface);
     }
 
     @MediumTest
     public void testSendAccessibilityEvent_AccessibilityEnabled() throws Exception {
-        // create an event to be dispatched
         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
 
-        // configure the mock service behavior
-        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
-                UserHandle.USER_OWNER)).andReturn(
-                        AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED);
-        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
-                UserHandle.USER_OWNER)).andReturn(true);
-        expect(mockServiceInterface.sendAccessibilityEvent(eqAccessibilityEvent(sentEvent),
-                UserHandle.USER_OWNER)).andReturn(false);
-        replay(mockServiceInterface);
+        when(mMockService.sendAccessibilityEvent(eq(sentEvent), anyInt()))
+                .thenReturn(true  /* should recycle event object */)
+                .thenReturn(false /* should not recycle event object */);
 
-        // invoke the method under test (manager and service in different processes)
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
-                UserHandle.USER_OWNER);
+        AccessibilityManager manager = createManager(true);
         manager.sendAccessibilityEvent(sentEvent);
 
-        // check expected result
-        AccessibilityEvent nextEventDifferentProcesses = AccessibilityEvent.obtain();
-        assertSame("The manager and the service are in different processes, so the event must be " +
-                "recycled", sentEvent, nextEventDifferentProcesses);
+        assertSame("The event should be recycled.", sentEvent, AccessibilityEvent.obtain());
 
-        // invoke the method under test (manager and service in the same process)
         manager.sendAccessibilityEvent(sentEvent);
 
-        // check expected result
-        AccessibilityEvent nextEventSameProcess = AccessibilityEvent.obtain();
-        assertNotSame("The manager and the service are in the same process, so the event must not" +
-                "be recycled", sentEvent, nextEventSameProcess);
-
-        // verify the mock service was properly called
-        verify(mockServiceInterface);
+        assertNotSame("The event should not be recycled.", sentEvent, AccessibilityEvent.obtain());
     }
 
     @MediumTest
     public void testSendAccessibilityEvent_AccessibilityDisabled() throws Exception {
-        // create an event to be dispatched
         AccessibilityEvent sentEvent = AccessibilityEvent.obtain();
 
-        // configure the mock service behavior
-        IAccessibilityManager mockServiceInterface = mMockServiceInterface;
-        expect(mockServiceInterface.addClient(anyIAccessibilityManagerClient(),
-                UserHandle.USER_OWNER)).andReturn(0);
-        replay(mockServiceInterface);
+        AccessibilityManager manager = createManager(false  /* disabled */);
 
-        // invoke the method under test (accessibility disabled)
-        AccessibilityManager manager = new AccessibilityManager(mContext, mockServiceInterface,
-                UserHandle.USER_OWNER);
         try {
             manager.sendAccessibilityEvent(sentEvent);
             fail("No accessibility events are sent if accessibility is disabled");
@@ -202,73 +158,5 @@
             // check expected result
             assertEquals("Accessibility off. Did you forget to check that?", ise.getMessage());
         }
-
-        // verify the mock service was properly called
-        verify(mockServiceInterface);
-    }
-
-    /**
-     * Determines if an {@link AccessibilityEvent} passed as a method argument
-     * matches expectations.
-     *
-     * @param matched The event to check.
-     * @return True if expectations are matched.
-     */
-    private static AccessibilityEvent eqAccessibilityEvent(AccessibilityEvent matched) {
-        reportMatcher(new AccessibilityEventMather(matched));
-        return null;
-    }
-
-    /**
-     * Determines if an {@link IAccessibilityManagerClient} passed as a method argument
-     * matches expectations which in this case are that any instance is accepted.
-     *
-     * @return <code>null</code>.
-     */
-    private static IAccessibilityManagerClient anyIAccessibilityManagerClient() {
-        reportMatcher(new AnyIAccessibilityManagerClientMather());
-        return null;
-    }
-
-    /**
-     * Matcher for {@link AccessibilityEvent}s.
-     */
-    private static class AccessibilityEventMather implements IArgumentMatcher {
-        private AccessibilityEvent mExpectedEvent;
-
-        public AccessibilityEventMather(AccessibilityEvent expectedEvent) {
-            mExpectedEvent = expectedEvent;
-        }
-
-        public boolean matches(Object matched) {
-            if (!(matched instanceof AccessibilityEvent)) {
-                return false;
-            }
-            AccessibilityEvent receivedEvent = (AccessibilityEvent) matched;
-            return mExpectedEvent.getEventType() == receivedEvent.getEventType();
-        }
-
-        public void appendTo(StringBuffer buffer) {
-            buffer.append("sendAccessibilityEvent()");
-            buffer.append(" with event type \"");
-            buffer.append(mExpectedEvent.getEventType());
-            buffer.append("\"");
-        }
-    }
-
-    /**
-     * Matcher for {@link IAccessibilityManagerClient}s.
-     */
-    private static class AnyIAccessibilityManagerClientMather implements IArgumentMatcher {
-        public boolean matches(Object matched) {
-            if (!(matched instanceof IAccessibilityManagerClient)) {
-                return false;
-            }
-            return true;
-        }
-
-        public void appendTo(StringBuffer buffer) {
-            buffer.append("addClient() with any IAccessibilityManagerClient");
-        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
index 1bc9b86..e1c5cee 100644
--- a/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
+++ b/services/tests/servicestests/src/com/android/server/MockAccessibilityService.java
@@ -62,7 +62,7 @@
      */
     public static AccessibilityServiceInfo createDefaultInfo() {
         AccessibilityServiceInfo defaultInfo = new AccessibilityServiceInfo();
-        defaultInfo.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED;
+        defaultInfo.eventTypes = AccessibilityEvent.TYPE_ANNOUNCEMENT;
         defaultInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_AUDIBLE;
         defaultInfo.flags = 0;
         defaultInfo.notificationTimeout = 0;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
deleted file mode 100644
index 7c3014c..0000000
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DeviceOwnerTest.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.devicepolicy;
-
-import android.content.ComponentName;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-/**
- * Tests for the DeviceOwner object that saves & loads device and policy owner information.
- * run this test with:
- *   make -j FrameworksServicesTests
- *   runtest --path frameworks/base/services/tests/servicestests/ \
- *       src/com/android/server/devicepolicy/DeviceOwnerTest.java
- */
-public class DeviceOwnerTest extends AndroidTestCase {
-
-    private ByteArrayInputStream mInputStreamForTest;
-    private final ByteArrayOutputStream mOutputStreamForTest = new ByteArrayOutputStream();
-
-    @SmallTest
-    public void testDeviceOwnerOnly() throws Exception {
-        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
-        out.setDeviceOwner("some.device.owner.package", "owner");
-        out.writeOwnerFile();
-
-        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
-        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
-        in.readOwnerFile();
-
-        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
-        assertEquals("owner", in.getDeviceOwnerName());
-        assertNull(in.getProfileOwnerComponent(1));
-    }
-
-    @SmallTest
-    public void testProfileOwnerOnly() throws Exception {
-        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
-        ComponentName admin = new ComponentName(
-            "some.profile.owner.package", "some.profile.owner.package.Class");
-        out.setProfileOwner(admin, "some-company", 1);
-        out.writeOwnerFile();
-
-        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
-        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
-        in.readOwnerFile();
-
-        assertNull(in.getDeviceOwnerPackageName());
-        assertNull(in.getDeviceOwnerName());
-        assertEquals(admin, in.getProfileOwnerComponent(1));
-        assertEquals("some-company", in.getProfileOwnerName(1));
-    }
-
-    @SmallTest
-    public void testDeviceAndProfileOwners() throws Exception {
-        DeviceOwner out = new DeviceOwner(null, mOutputStreamForTest);
-        ComponentName profileAdmin = new ComponentName(
-            "some.profile.owner.package", "some.profile.owner.package.Class");
-        ComponentName otherProfileAdmin = new ComponentName(
-            "some.other.profile.owner", "some.other.profile.owner.OtherClass");
-        // Old code used package name rather than component name, so the class
-        // bit could be empty.
-        ComponentName legacyComponentName = new ComponentName("legacy.profile.owner.package", "");
-        out.setDeviceOwner("some.device.owner.package", "owner");
-        out.setProfileOwner(profileAdmin, "some-company", 1);
-        out.setProfileOwner(otherProfileAdmin, "some-other-company", 2);
-        out.setProfileOwner(legacyComponentName, "legacy-company", 3);
-        out.writeOwnerFile();
-
-        mInputStreamForTest = new ByteArrayInputStream(mOutputStreamForTest.toByteArray());
-
-        DeviceOwner in = new DeviceOwner(mInputStreamForTest, null);
-        in.readOwnerFile();
-
-        assertEquals("some.device.owner.package", in.getDeviceOwnerPackageName());
-        assertEquals("owner", in.getDeviceOwnerName());
-        assertEquals(profileAdmin, in.getProfileOwnerComponent(1));
-        assertEquals("some-company", in.getProfileOwnerName(1));
-        assertEquals(otherProfileAdmin, in.getProfileOwnerComponent(2));
-        assertEquals("some-other-company", in.getProfileOwnerName(2));
-        assertEquals(legacyComponentName, in.getProfileOwnerComponent(3));
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
new file mode 100644
index 0000000..c2b8981
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -0,0 +1,46 @@
+/*
+ * 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.devicepolicy;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.os.UserManager;
+
+import static org.mockito.Mockito.mock;
+
+public class DpmMockContext extends ContextWrapper {
+    private final UserManager mMockUserManager;
+
+
+    public DpmMockContext(Context context) {
+        super(context);
+        mMockUserManager = mock(UserManager.class);
+    }
+
+    public UserManager getMockUserManager() {
+        return mMockUserManager;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        switch (name) {
+            case Context.USER_SERVICE:
+                return mMockUserManager;
+        }
+        return super.getSystemService(name);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
new file mode 100644
index 0000000..445260b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+
+public class DpmTestBase extends AndroidTestCase {
+    private DpmMockContext mMockContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mMockContext = new DpmMockContext(super.getContext());
+    }
+
+    @Override
+    public DpmMockContext getContext() {
+        return mMockContext;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
new file mode 100644
index 0000000..a284ca0
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.os.FileUtils;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+
+import junit.framework.Assert;
+
+import static org.mockito.Mockito.when;
+
+/**
+ * Tests for the DeviceOwner object that saves & loads device and policy owner information.
+ * run this test with:
+ mmma frameworks/base/services/tests/servicestests/ &&
+ adb install \
+   -r out/target/product/hammerhead/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.devicepolicy.OwnersTest \
+   -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+public class OwnersTest extends DpmTestBase {
+    private static final String TAG = "DeviceOwnerTest";
+
+    private static final String LEGACY_FILE = "legacy.xml";
+    private static final String DEVICE_OWNER_FILE = "device_owner2.xml";
+    private static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
+
+    private File mDataDir;
+
+    private class OwnersSub extends Owners {
+        final File mLegacyFile;
+        final File mDeviceOwnerFile;
+        final File mProfileOwnerBase;
+
+        public OwnersSub() {
+            super(getContext());
+            mLegacyFile = new File(mDataDir, LEGACY_FILE);
+            mDeviceOwnerFile = new File(mDataDir, DEVICE_OWNER_FILE);
+            mProfileOwnerBase = new File(mDataDir, PROFILE_OWNER_FILE_BASE);
+        }
+
+        @Override
+        File getLegacyConfigFileWithTestOverride() {
+            return mLegacyFile;
+        }
+
+        @Override
+        File getDeviceOwnerFileWithTestOverride() {
+            return mDeviceOwnerFile;
+        }
+
+        @Override
+        File getProfileOwnerFileWithTestOverride(int userId) {
+            return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mDataDir = new File(getContext().getCacheDir(), "OwnersTest");
+        if (mDataDir.exists()) {
+            assertTrue("failed to delete dir", FileUtils.deleteContents(mDataDir));
+        }
+        mDataDir.mkdirs();
+        Log.i(TAG, "Created " + mDataDir);
+    }
+
+    private String readAsset(String assetPath) throws IOException {
+        final StringBuilder sb = new StringBuilder();
+        try (BufferedReader br = new BufferedReader(
+                new InputStreamReader((getContext().getResources().getAssets().open(assetPath))))) {
+            String line;
+            while ((line = br.readLine()) != null) {
+                sb.append(line);
+                sb.append(System.lineSeparator());
+            }
+        }
+        return sb.toString();
+    }
+
+    private void createLegacyFile(File path, String content)
+            throws IOException {
+        path.getParentFile().mkdirs();
+
+        try (FileWriter writer = new FileWriter(path)) {
+            Log.i(TAG, "Writing to " + path);
+            Log.i(TAG, content);
+            writer.write(content);
+        }
+    }
+
+    private void addUsersToUserManager(int... userIds) {
+        final ArrayList<UserInfo> userInfos = new ArrayList<>();
+        for (int userId : userIds) {
+            final UserInfo ui = new UserInfo();
+            ui.id = userId;
+            userInfos.add(ui);
+        }
+        when(getContext().getMockUserManager().getUsers()).thenReturn(userInfos);
+    }
+
+    public void testUpgrade01() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test01/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            // File was empty, so no new files should be created.
+            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade02() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test02/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists()); // TODO Check content
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertTrue(owners.hasDeviceOwner());
+            assertEquals(null, owners.getDeviceOwnerName());
+            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
+
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade03() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test03/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertNull(owners.getSystemUpdatePolicy());
+
+            assertEquals(2, owners.getProfileOwnerKeys().size());
+            assertEquals(new ComponentName("com.google.android.testdpc",
+                            "com.google.android.testdpc.DeviceAdminReceiver0"),
+                    owners.getProfileOwnerComponent(10));
+            assertEquals("0", owners.getProfileOwnerName(10));
+            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
+
+            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
+                    owners.getProfileOwnerComponent(11));
+            assertEquals("1", owners.getProfileOwnerName(11));
+            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+        }
+    }
+
+    public void testUpgrade04() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(21).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertTrue(owners.hasDeviceOwner());
+            assertEquals(null, owners.getDeviceOwnerName());
+            assertEquals("com.google.android.testdpc", owners.getDeviceOwnerPackageName());
+
+            assertTrue(owners.hasDeviceInitializer());
+            assertEquals("com.google.android.testdpcx", owners.getDeviceInitializerPackageName());
+            assertNotNull(owners.getSystemUpdatePolicy());
+            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+
+            assertEquals(2, owners.getProfileOwnerKeys().size());
+            assertEquals(new ComponentName("com.google.android.testdpc",
+                            "com.google.android.testdpc.DeviceAdminReceiver0"),
+                    owners.getProfileOwnerComponent(10));
+            assertEquals("0", owners.getProfileOwnerName(10));
+            assertEquals("com.google.android.testdpc", owners.getProfileOwnerPackage(10));
+
+            assertEquals(new ComponentName("com.google.android.testdpc1", ""),
+                    owners.getProfileOwnerComponent(11));
+            assertEquals("1", owners.getProfileOwnerName(11));
+            assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
+        }
+    }
+
+    public void testUpgrade05() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test05/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+
+            assertTrue(owners.hasDeviceInitializer());
+            assertEquals("com.google.android.testdpcx", owners.getDeviceInitializerPackageName());
+
+            assertNull(owners.getSystemUpdatePolicy());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+        }
+    }
+
+    public void testUpgrade06() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        // First, migrate.
+        {
+            final OwnersSub owners = new OwnersSub();
+
+            createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test06/input.xml"));
+
+            owners.load();
+
+            // The legacy file should be removed.
+            assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+            assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+            assertFalse(owners.getProfileOwnerFileWithTestOverride(20).exists());
+        }
+
+        // Then re-read and check.
+        {
+            final OwnersSub owners = new OwnersSub();
+            owners.load();
+
+            assertFalse(owners.hasDeviceOwner());
+            assertFalse(owners.hasDeviceInitializer());
+            assertEquals(0, owners.getProfileOwnerKeys().size());
+
+            assertNotNull(owners.getSystemUpdatePolicy());
+            assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
+        }
+    }
+
+    public void testRemoveExistingFiles() throws Exception {
+        addUsersToUserManager(10, 11, 20, 21);
+
+        final OwnersSub owners = new OwnersSub();
+
+        // First, migrate to create new-style config files.
+        createLegacyFile(owners.mLegacyFile, readAsset("OwnersTest/test04/input.xml"));
+
+        owners.load();
+
+        assertFalse(owners.getLegacyConfigFileWithTestOverride().exists());
+
+        assertTrue(owners.getDeviceOwnerFileWithTestOverride().exists());
+        assertTrue(owners.getProfileOwnerFileWithTestOverride(10).exists());
+        assertTrue(owners.getProfileOwnerFileWithTestOverride(11).exists());
+
+        // Then clear all information and save.
+        owners.clearDeviceInitializer();
+        owners.clearDeviceOwner();
+        owners.clearSystemUpdatePolicy();
+        owners.removeProfileOwner(10);
+        owners.removeProfileOwner(11);
+
+        owners.writeDeviceOwner();
+        owners.writeProfileOwner(10);
+        owners.writeProfileOwner(11);
+        owners.writeProfileOwner(20);
+        owners.writeProfileOwner(21);
+
+        // Now all files should be removed.
+        assertFalse(owners.getDeviceOwnerFileWithTestOverride().exists());
+        assertFalse(owners.getProfileOwnerFileWithTestOverride(10).exists());
+        assertFalse(owners.getProfileOwnerFileWithTestOverride(11).exists());
+    }
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 2d31a78..8a1a553 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -206,8 +206,14 @@
          */
         public static final int CAPABILITY_CAN_PAUSE_VIDEO = 0x00100000;
 
+        /**
+         * Call sends responses through connection.
+         * @hide
+         */
+        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
         //******************************************************************************************
-        // Next CAPABILITY value: 0x00004000
+        // Next CAPABILITY value: 0x00800000
         //******************************************************************************************
 
         /**
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 7b277c5..430760a 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -248,8 +248,15 @@
      */
     public static final int CAPABILITY_CONFERENCE_HAS_NO_CHILDREN = 0x00200000;
 
+    /**
+     * Indicates that the connection itself wants to handle any sort of reply response, rather than
+     * relying on SMS.
+     * @hide
+     */
+    public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x00400000
+    // Next CAPABILITY value: 0x00800000
     //**********************************************************************************************
 
     /**
@@ -388,6 +395,10 @@
         if (can(capabilities, CAPABILITY_CONFERENCE_HAS_NO_CHILDREN)) {
             builder.append(" CAPABILITY_SINGLE_PARTY_CONFERENCE");
         }
+        if (can(capabilities, CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION)) {
+            builder.append(" CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION");
+        }
+
         builder.append("]");
         return builder.toString();
     }
@@ -1763,6 +1774,13 @@
     public void onReject() {}
 
     /**
+     * Notifies ths Connection of a request reject with a message.
+     *
+     * @hide
+     */
+    public void onReject(String replyMessage) {}
+
+    /**
      * Notifies this Connection whether the user wishes to proceed with the post-dial DTMF codes.
      */
     public void onPostDialContinue(boolean proceed) {}
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 383e45b..4e330bdb 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -101,6 +101,7 @@
     private static final int MSG_ANSWER_VIDEO = 17;
     private static final int MSG_MERGE_CONFERENCE = 18;
     private static final int MSG_SWAP_CONFERENCE = 19;
+    private static final int MSG_REJECT_WITH_MESSAGE = 20;
 
     private static Connection sNullConnection;
 
@@ -166,6 +167,14 @@
         }
 
         @Override
+        public void rejectWithMessage(String callId, String message) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = callId;
+            args.arg2 = message;
+            mHandler.obtainMessage(MSG_REJECT_WITH_MESSAGE, args).sendToTarget();
+        }
+
+        @Override
         public void disconnect(String callId) {
             mHandler.obtainMessage(MSG_DISCONNECT, callId).sendToTarget();
         }
@@ -296,6 +305,15 @@
                 case MSG_REJECT:
                     reject((String) msg.obj);
                     break;
+                case MSG_REJECT_WITH_MESSAGE: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    try {
+                        reject((String) args.arg1, (String) args.arg2);
+                    } finally {
+                        args.recycle();
+                    }
+                    break;
+                }
                 case MSG_DISCONNECT:
                     disconnect((String) msg.obj);
                     break;
@@ -681,6 +699,11 @@
         findConnectionForAction(callId, "reject").onReject();
     }
 
+    private void reject(String callId, String rejectWithMessage) {
+        Log.d(this, "reject %s with message", callId);
+        findConnectionForAction(callId, "reject").onReject(rejectWithMessage);
+    }
+
     private void disconnect(String callId) {
         Log.d(this, "disconnect %s", callId);
         if (mConnectionById.containsKey(callId)) {
diff --git a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
index c2e8530..dd253cf 100644
--- a/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IConnectionService.aidl
@@ -50,6 +50,8 @@
 
     void reject(String callId);
 
+    void rejectWithMessage(String callId, String message);
+
     void disconnect(String callId);
 
     void hold(String callId);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e3f3c75..aa750ef 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -372,6 +372,12 @@
     public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
 
     /**
+     * Determine whether user can toggle Enhanced 4G LTE Mode in Settings.
+     * @hide
+     */
+    public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool";
+
+    /**
      * If this is true, the SIM card (through Customer Service Profile EF file) will be able to
      * prevent manual operator selection. If false, this SIM setting will be ignored and manual
      * operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -413,6 +419,15 @@
     public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl";
     public static final String KEY_MMS_USER_AGENT_STRING = "userAgent";
 
+    /**
+     * Determines whether the carrier supports making non-emergency phone calls while the phone is
+     * in emergency callback mode.  Default value is {@code true}, meaning that non-emergency calls
+     * are allowed in emergency callback mode.
+     * @hide
+     */
+    public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL =
+            "allow_non_emergency_calls_in_ecm_bool";
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -473,6 +488,7 @@
         sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0);
         sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100);
         sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true);
+        sDefaults.putBoolean(KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, true);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
@@ -506,6 +522,7 @@
         sDefaults.putString(KEY_MMS_UA_PROF_TAG_NAME_STRING, "x-wap-profile");
         sDefaults.putString(KEY_MMS_UA_PROF_URL_STRING, "");
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
+        sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
     }
 
     /**
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 273cc93..b430340 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1457,10 +1457,15 @@
         String result = null;
         try {
             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
+            /**
+             * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+             * country code to corresponding national format which would replace the leading
+             * +82 with 0.
+             */
             if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
-                    (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE))) {
-                // Format local Korean phone numbers with country code to corresponding national
-                // format which would replace the leading +82 with 0.
+                    (pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
+                    (pn.getCountryCodeSource() ==
+                            PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
                 result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
             } else {
                 result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java
index 0c5c557..2bfaf1b 100644
--- a/telephony/java/android/telephony/RadioAccessFamily.java
+++ b/telephony/java/android/telephony/RadioAccessFamily.java
@@ -185,6 +185,36 @@
             case RILConstants.NETWORK_MODE_GLOBAL:
                 raf = GSM | WCDMA | CDMA | EVDO;
                 break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_ONLY:
+                raf = RAF_TD_SCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_WCDMA:
+                raf = RAF_TD_SCDMA | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA:
+                raf = RAF_LTE | RAF_TD_SCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_GSM:
+                raf = RAF_TD_SCDMA | GSM;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM:
+                raf = RAF_LTE | RAF_TD_SCDMA | GSM;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
+                raf = RAF_TD_SCDMA | GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA:
+                raf = RAF_LTE | RAF_TD_SCDMA | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA:
+                raf = RAF_LTE | RAF_TD_SCDMA | GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
+                raf = RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
+                break;
+            case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
+                raf = RAF_LTE | RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA;
+                break;
             default:
                 raf = RAF_UNKNOWN;
                 break;
@@ -248,6 +278,36 @@
             case (GSM | WCDMA | CDMA | EVDO):
                 type = RILConstants.NETWORK_MODE_GLOBAL;
                 break;
+            case RAF_TD_SCDMA:
+                type = RILConstants.NETWORK_MODE_TDSCDMA_ONLY;
+                break;
+            case (RAF_TD_SCDMA | WCDMA):
+                type = RILConstants.NETWORK_MODE_TDSCDMA_WCDMA;
+                break;
+            case (RAF_LTE | RAF_TD_SCDMA):
+                type = RILConstants.NETWORK_MODE_LTE_TDSCDMA;
+                break;
+            case (RAF_TD_SCDMA | GSM):
+                type = RILConstants.NETWORK_MODE_TDSCDMA_GSM;
+                break;
+            case (RAF_LTE | RAF_TD_SCDMA | GSM):
+                type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM;
+                break;
+            case (RAF_TD_SCDMA | GSM | WCDMA):
+                type = RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA;
+                break;
+            case (RAF_LTE | RAF_TD_SCDMA | WCDMA):
+                type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA;
+                break;
+            case (RAF_LTE | RAF_TD_SCDMA | GSM | WCDMA):
+                type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA;
+                break;
+            case (RAF_TD_SCDMA | CDMA | EVDO | GSM | WCDMA):
+                type = RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+                break;
+            case (RAF_LTE | RAF_TD_SCDMA | RAF_LTE | CDMA | EVDO | GSM | WCDMA):
+                type = RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA;
+                break;
             default:
                 type = RILConstants.PREFERRED_NETWORK_MODE ;
                 break;
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 80515cf..1337487 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -731,6 +731,9 @@
             case RIL_RADIO_TECHNOLOGY_IWLAN:
                 rtString = "IWLAN";
                 break;
+            case RIL_RADIO_TECHNOLOGY_TD_SCDMA:
+                rtString = "TD-SCDMA";
+                break;
             default:
                 rtString = "Unexpected";
                 Rlog.w(LOG_TAG, "Unexpected radioTechnology=" + rt);
@@ -1068,6 +1071,8 @@
             return TelephonyManager.NETWORK_TYPE_HSPAP;
         case ServiceState.RIL_RADIO_TECHNOLOGY_GSM:
             return TelephonyManager.NETWORK_TYPE_GSM;
+        case ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA:
+            return TelephonyManager.NETWORK_TYPE_TD_SCDMA;
         case ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN:
             return TelephonyManager.NETWORK_TYPE_IWLAN;
         default:
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index f02d109..f535e5d 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -68,6 +68,7 @@
     private int mLteRsrq;
     private int mLteRssnr;
     private int mLteCqi;
+    private int mTdScdmaRscp;
 
     private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult
 
@@ -107,6 +108,7 @@
         mLteRsrq = INVALID;
         mLteRssnr = INVALID;
         mLteCqi = INVALID;
+        mTdScdmaRscp = INVALID;
         isGsm = true;
     }
 
@@ -131,6 +133,7 @@
         mLteRsrq = INVALID;
         mLteRssnr = INVALID;
         mLteCqi = INVALID;
+        mTdScdmaRscp = INVALID;
         isGsm = gsmFlag;
     }
 
@@ -143,6 +146,22 @@
             int cdmaDbm, int cdmaEcio,
             int evdoDbm, int evdoEcio, int evdoSnr,
             int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
+            int tdScdmaRscp, boolean gsmFlag) {
+        initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
+                evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
+                lteRsrq, lteRssnr, lteCqi, gsmFlag);
+        mTdScdmaRscp = tdScdmaRscp;
+    }
+
+    /**
+     * Constructor
+     *
+     * @hide
+     */
+    public SignalStrength(int gsmSignalStrength, int gsmBitErrorRate,
+            int cdmaDbm, int cdmaEcio,
+            int evdoDbm, int evdoEcio, int evdoSnr,
+            int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
             boolean gsmFlag) {
         initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
                 evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
@@ -233,6 +252,7 @@
         mLteRsrq = lteRsrq;
         mLteRssnr = lteRssnr;
         mLteCqi = lteCqi;
+        mTdScdmaRscp = INVALID;
         isGsm = gsm;
         if (DBG) log("initialize: " + toString());
     }
@@ -253,6 +273,7 @@
         mLteRsrq = s.mLteRsrq;
         mLteRssnr = s.mLteRssnr;
         mLteCqi = s.mLteCqi;
+        mTdScdmaRscp = s.mTdScdmaRscp;
         isGsm = s.isGsm;
     }
 
@@ -276,6 +297,7 @@
         mLteRsrq = in.readInt();
         mLteRssnr = in.readInt();
         mLteCqi = in.readInt();
+        mTdScdmaRscp = in.readInt();
         isGsm = (in.readInt() != 0);
     }
 
@@ -302,7 +324,7 @@
         ss.mLteRsrq = in.readInt();
         ss.mLteRssnr = in.readInt();
         ss.mLteCqi = in.readInt();
-
+        ss.mTdScdmaRscp = in.readInt();
         return ss;
     }
 
@@ -322,6 +344,7 @@
         out.writeInt(mLteRsrq);
         out.writeInt(mLteRssnr);
         out.writeInt(mLteCqi);
+        out.writeInt(mTdScdmaRscp);
         out.writeInt(isGsm ? 1 : 0);
     }
 
@@ -377,6 +400,9 @@
         mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID;
         mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr
                 : SignalStrength.INVALID;
+
+        mTdScdmaRscp = ((mTdScdmaRscp >= 25) && (mTdScdmaRscp <= 120))
+                ? -mTdScdmaRscp : SignalStrength.INVALID;
         // Cqi no change
         if (DBG) log("Signal after validate=" + this);
     }
@@ -477,12 +503,15 @@
      *     while 4 represents a very strong signal strength.
      */
     public int getLevel() {
-        int level;
+        int level = 0;
 
         if (isGsm) {
             level = getLteLevel();
             if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                level = getGsmLevel();
+                level = getTdScdmaLevel();
+                if (level == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    level = getGsmLevel();
+                }
             }
         } else {
             int cdmaLevel = getCdmaLevel();
@@ -508,10 +537,14 @@
      * @hide
      */
     public int getAsuLevel() {
-        int asuLevel;
+        int asuLevel = 0;
         if (isGsm) {
             if (getLteLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
-                asuLevel = getGsmAsuLevel();
+                if (getTdScdmaLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    asuLevel = getGsmAsuLevel();
+                } else {
+                    asuLevel = getTdScdmaAsuLevel();
+                }
             } else {
                 asuLevel = getLteAsuLevel();
             }
@@ -539,12 +572,16 @@
      * @hide
      */
     public int getDbm() {
-        int dBm;
+        int dBm = INVALID;
 
         if(isGsm()) {
             dBm = getLteDbm();
             if (dBm == INVALID) {
-                dBm = getGsmDbm();
+                if (getTdScdmaLevel() == SIGNAL_STRENGTH_NONE_OR_UNKNOWN) {
+                    dBm = getGsmDbm();
+                } else {
+                    dBm = getTdScdmaDbm();
+                }
             }
         } else {
             int cdmaDbm = getCdmaDbm();
@@ -849,6 +886,54 @@
     }
 
     /**
+     * @return get TD_SCDMA dbm
+     *
+     * @hide
+     */
+    public int getTdScdmaDbm() {
+        return this.mTdScdmaRscp;
+    }
+
+    /**
+     * Get TD-SCDMA as level 0..4
+     * Range : 25 to 120
+     * INT_MAX: 0x7FFFFFFF denotes invalid value
+     * Reference: 3GPP TS 25.123, section 9.1.1.1
+     *
+     * @hide
+     */
+    public int getTdScdmaLevel() {
+        final int tdScdmaDbm = getTdScdmaDbm();
+        int level;
+
+        if ((tdScdmaDbm > -25) || (tdScdmaDbm == SignalStrength.INVALID))
+                level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (tdScdmaDbm >= -49) level = SIGNAL_STRENGTH_GREAT;
+        else if (tdScdmaDbm >= -73) level = SIGNAL_STRENGTH_GOOD;
+        else if (tdScdmaDbm >= -97) level = SIGNAL_STRENGTH_MODERATE;
+        else if (tdScdmaDbm >= -120) level = SIGNAL_STRENGTH_POOR;
+        else level = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+
+        if (DBG) log("getTdScdmaLevel = " + level);
+        return level;
+     }
+
+    /**
+     * Get the TD-SCDMA signal level as an asu value.
+     *
+     * @hide
+     */
+    public int getTdScdmaAsuLevel() {
+        final int tdScdmaDbm = getTdScdmaDbm();
+        int tdScdmaAsuLevel;
+
+        if (tdScdmaDbm == INVALID) tdScdmaAsuLevel = 255;
+        else tdScdmaAsuLevel = tdScdmaDbm + 120;
+        if (DBG) log("TD-SCDMA Asu level: " + tdScdmaAsuLevel);
+        return tdScdmaAsuLevel;
+    }
+
+   /**
      * @return hash code
      */
     @Override
@@ -860,7 +945,7 @@
                 + (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum)
                 + (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
                 + (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
-                + (isGsm ? 1 : 0));
+                + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0));
     }
 
     /**
@@ -892,6 +977,7 @@
                 && mLteRsrq == s.mLteRsrq
                 && mLteRssnr == s.mLteRssnr
                 && mLteCqi == s.mLteCqi
+                && mTdScdmaRscp == s.mTdScdmaRscp
                 && isGsm == s.isGsm);
     }
 
@@ -913,6 +999,7 @@
                 + " " + mLteRsrq
                 + " " + mLteRssnr
                 + " " + mLteCqi
+                + " " + mTdScdmaRscp
                 + " " + (isGsm ? "gsm|lte" : "cdma"));
     }
 
@@ -935,6 +1022,7 @@
         mLteRsrq = m.getInt("LteRsrq");
         mLteRssnr = m.getInt("LteRssnr");
         mLteCqi = m.getInt("LteCqi");
+        mTdScdmaRscp = m.getInt("TdScdma");
         isGsm = m.getBoolean("isGsm");
     }
 
@@ -957,6 +1045,7 @@
         m.putInt("LteRsrq", mLteRsrq);
         m.putInt("LteRssnr", mLteRssnr);
         m.putInt("LteCqi", mLteCqi);
+        m.putInt("TdScdma", mTdScdmaRscp);
         m.putBoolean("isGsm", Boolean.valueOf(isGsm));
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index e104b38..f6e4bed 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1099,11 +1099,21 @@
         case RILConstants.NETWORK_MODE_LTE_GSM_WCDMA:
         case RILConstants.NETWORK_MODE_LTE_WCDMA:
         case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_TDSCDMA_ONLY:
+        case RILConstants.NETWORK_MODE_TDSCDMA_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_TDSCDMA:
+        case RILConstants.NETWORK_MODE_TDSCDMA_GSM:
+        case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM:
+        case RILConstants.NETWORK_MODE_TDSCDMA_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_TDSCDMA_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA:
+        case RILConstants.NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_GSM;
 
         // Use CDMA Phone for the global mode including CDMA
         case RILConstants.NETWORK_MODE_GLOBAL:
         case RILConstants.NETWORK_MODE_LTE_CDMA_EVDO:
+        case RILConstants.NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA:
             return PhoneConstants.PHONE_TYPE_CDMA;
 
         case RILConstants.NETWORK_MODE_LTE_ONLY:
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index a6a2658..23a69d1 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -71,7 +71,7 @@
      * @param disabledFeatures features disabled as defined in com.android.ims.ImsConfig#FeatureConstants.
      */
     void registrationFeatureCapabilityChanged(int serviceClass,
-            out int[] enabledFeatures, out int[] disabledFeatures);
+            in int[] enabledFeatures, in int[] disabledFeatures);
 
     /**
      * Updates the application with the waiting voice message count.
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8d48c86..7088be8 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -96,6 +96,16 @@
     int NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA = 10; /* LTE, CDMA, EvDo, GSM/WCDMA */
     int NETWORK_MODE_LTE_ONLY       = 11; /* LTE Only mode. */
     int NETWORK_MODE_LTE_WCDMA      = 12; /* LTE/WCDMA */
+    int NETWORK_MODE_TDSCDMA_ONLY            = 13; /* TD-SCDMA only */
+    int NETWORK_MODE_TDSCDMA_WCDMA           = 14; /* TD-SCDMA and WCDMA */
+    int NETWORK_MODE_LTE_TDSCDMA             = 15; /* TD-SCDMA and LTE */
+    int NETWORK_MODE_TDSCDMA_GSM             = 16; /* TD-SCDMA and GSM */
+    int NETWORK_MODE_LTE_TDSCDMA_GSM         = 17; /* TD-SCDMA,GSM and LTE */
+    int NETWORK_MODE_TDSCDMA_GSM_WCDMA       = 18; /* TD-SCDMA, GSM/WCDMA */
+    int NETWORK_MODE_LTE_TDSCDMA_WCDMA       = 19; /* TD-SCDMA, WCDMA and LTE */
+    int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA   = 20; /* TD-SCDMA, GSM/WCDMA and LTE */
+    int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA  = 21; /*TD-SCDMA,EvDo,CDMA,GSM/WCDMA*/
+    int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; /* TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo */
     int PREFERRED_NETWORK_MODE      = SystemProperties.getInt("ro.telephony.default_network",
             NETWORK_MODE_WCDMA_PREF);
 
diff --git a/tests/TileBenchmark/Android.mk b/tests/SurfaceComposition/Android.mk
similarity index 60%
rename from tests/TileBenchmark/Android.mk
rename to tests/SurfaceComposition/Android.mk
index 9a057af..95f69f1 100644
--- a/tests/TileBenchmark/Android.mk
+++ b/tests/SurfaceComposition/Android.mk
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 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.
@@ -12,17 +12,23 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-LOCAL_PATH := $(call my-dir)
+LOCAL_PATH:= $(call my-dir)
+
 include $(CLEAR_VARS)
 
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES :=
-
-LOCAL_PACKAGE_NAME := TileBenchmark
-
+# Don't include this package in any target
 LOCAL_MODULE_TAGS := tests
+# When built, explicitly put it in the data partition.
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
 
-LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := SurfaceComposition
+
+LOCAL_SDK_VERSION := current
 
 include $(BUILD_PACKAGE)
diff --git a/tests/SurfaceComposition/AndroidManifest.xml b/tests/SurfaceComposition/AndroidManifest.xml
new file mode 100644
index 0000000..4c0a9b6
--- /dev/null
+++ b/tests/SurfaceComposition/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.surfacecomposition">
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <application android:theme="@style/noeffects">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.surfacecomposition.SurfaceCompositionMeasuringActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.surfacecomposition">
+    </instrumentation>
+</manifest>
diff --git a/tests/SurfaceComposition/res/values/themes.xml b/tests/SurfaceComposition/res/values/themes.xml
new file mode 100644
index 0000000..254d707
--- /dev/null
+++ b/tests/SurfaceComposition/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?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.
+ -->
+<resources>
+    <style name="noeffects" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:fadingEdge">none</item>
+        <item name="android:windowContentTransitions">false</item>
+        <item name="android:windowAnimationStyle">@null</item>
+    </style>
+</resources>
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java b/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java
new file mode 100644
index 0000000..d626f10
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/CustomLayout.java
@@ -0,0 +1,48 @@
+/*
+ * 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.surfacecomposition;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class CustomLayout extends ViewGroup {
+    public CustomLayout(Context context) {
+        super(context);
+    }
+
+    public static class LayoutParams extends ViewGroup.LayoutParams {
+        private int mLeft, mTop, mRight, mBottom;
+
+        public LayoutParams(int left, int top, int right, int bottom) {
+            super(0, 0);
+            mLeft = left;
+            mTop = top;
+            mRight = right;
+            mBottom = bottom;
+        }
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            View child = getChildAt(i);
+            CustomLayout.LayoutParams lp = (CustomLayout.LayoutParams) child.getLayoutParams();
+            child.layout(lp.mLeft, lp.mTop, lp.mRight, lp.mBottom);
+        }
+    }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java b/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java
new file mode 100644
index 0000000..0430662
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/CustomSurfaceView.java
@@ -0,0 +1,243 @@
+/*
+ * 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.surfacecomposition;
+
+import java.util.Random;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * This provides functionality to measure Surface update frame rate. The idea is to
+ * constantly invalidates Surface in a separate thread. Lowest possible way is to
+ * use SurfaceView which works with Surface. This gives a very small overhead
+ * and very close to Android internals. Note, that lockCanvas is blocking
+ * methods and it returns once SurfaceFlinger consumes previous buffer. This
+ * gives the change to measure real performance of Surface compositor.
+ */
+public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+    private final static long DURATION_TO_WARMUP_MS = 50;
+    private final static long DURATION_TO_MEASURE_ROUGH_MS = 500;
+    private final static long DURATION_TO_MEASURE_PRECISE_MS = 3000;
+    private final static Random mRandom = new Random();
+
+    private final Object mSurfaceLock = new Object();
+    private Surface mSurface;
+    private boolean mDrawNameOnReady = true;
+    private boolean mSurfaceWasChanged = false;
+    private String mName;
+    private Canvas mCanvas;
+
+    class ValidateThread extends Thread {
+        private double mFPS = 0.0f;
+        // Used to support early exit and prevent long computation.
+        private double mBadFPS;
+        private double mPerfectFPS;
+
+        ValidateThread(double badFPS, double perfectFPS) {
+            mBadFPS = badFPS;
+            mPerfectFPS = perfectFPS;
+        }
+
+        public void run() {
+            long startTime = System.currentTimeMillis();
+            while (System.currentTimeMillis() - startTime < DURATION_TO_WARMUP_MS) {
+                invalidateSurface(false);
+            }
+
+            startTime = System.currentTimeMillis();
+            long endTime;
+            int frameCnt = 0;
+            while (true) {
+                invalidateSurface(false);
+                endTime = System.currentTimeMillis();
+                ++frameCnt;
+                mFPS = (double)frameCnt * 1000.0 / (endTime - startTime);
+                if ((endTime - startTime) >= DURATION_TO_MEASURE_ROUGH_MS) {
+                    // Test if result looks too bad or perfect and stop early.
+                    if (mFPS <= mBadFPS || mFPS >= mPerfectFPS) {
+                        break;
+                    }
+                }
+                if ((endTime - startTime) >= DURATION_TO_MEASURE_PRECISE_MS) {
+                    break;
+                }
+            }
+        }
+
+        public double getFPS() {
+            return mFPS;
+        }
+    }
+
+    public CustomSurfaceView(Context context, String name) {
+        super(context);
+        mName = name;
+        getHolder().addCallback(this);
+    }
+
+    public void setMode(int pixelFormat, boolean drawNameOnReady) {
+        mDrawNameOnReady = drawNameOnReady;
+        getHolder().setFormat(pixelFormat);
+    }
+
+    public void acquireCanvas() {
+        synchronized (mSurfaceLock) {
+            if (mCanvas != null) {
+                throw new RuntimeException("Surface canvas was already acquired.");
+            }
+            if (mSurface != null) {
+                mCanvas = mSurface.lockCanvas(null);
+            }
+        }
+    }
+
+    public void releaseCanvas() {
+        synchronized (mSurfaceLock) {
+            if (mCanvas != null) {
+                if (mSurface == null) {
+                    throw new RuntimeException(
+                            "Surface was destroyed but canvas was not released.");
+                }
+                mSurface.unlockCanvasAndPost(mCanvas);
+                mCanvas = null;
+            }
+        }
+    }
+
+    /**
+     * Invalidate surface.
+     */
+    private void invalidateSurface(boolean drawSurfaceId) {
+        synchronized (mSurfaceLock) {
+            if (mSurface != null) {
+                Canvas canvas = mSurface.lockCanvas(null);
+                // Draw surface name for debug purpose only. This does not affect the test
+                // because it is drawn only during allocation.
+                if (drawSurfaceId) {
+                    int textSize = canvas.getHeight() / 24;
+                    Paint paint = new Paint();
+                    paint.setTextSize(textSize);
+                    int textWidth = (int)(paint.measureText(mName) + 0.5f);
+                    int x = mRandom.nextInt(canvas.getWidth() - textWidth);
+                    int y = textSize + mRandom.nextInt(canvas.getHeight() - textSize);
+                    // Create effect of fog to visually control correctness of composition.
+                    paint.setColor(0xFFFF8040);
+                    canvas.drawARGB(32, 255, 255, 255);
+                    canvas.drawText(mName, x, y, paint);
+                }
+                mSurface.unlockCanvasAndPost(canvas);
+            }
+        }
+    }
+
+    /**
+     * Wait until surface is created and ready to use or return immediately if surface
+     * already exists.
+     */
+    public void waitForSurfaceReady() {
+        synchronized (mSurfaceLock) {
+            if (mSurface == null) {
+                try {
+                    mSurfaceLock.wait(5000);
+                } catch(InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (mSurface == null)
+                throw new RuntimeException("Surface is not ready.");
+            mSurfaceWasChanged = false;
+        }
+    }
+
+    /**
+     * Wait until surface is destroyed or return immediately if surface does not exist.
+     */
+    public void waitForSurfaceDestroyed() {
+        synchronized (mSurfaceLock) {
+            if (mSurface != null) {
+                try {
+                    mSurfaceLock.wait(5000);
+                } catch(InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (mSurface != null)
+                throw new RuntimeException("Surface still exists.");
+            mSurfaceWasChanged = false;
+        }
+    }
+
+    /**
+     * Validate that surface has not been changed since waitForSurfaceReady or
+     * waitForSurfaceDestroyed.
+     */
+    public void validateSurfaceNotChanged() {
+        synchronized (mSurfaceLock) {
+            if (mSurfaceWasChanged) {
+                throw new RuntimeException("Surface was changed during the test execution.");
+            }
+        }
+    }
+
+    public double measureFPS(double badFPS, double perfectFPS) {
+        try {
+            ValidateThread validateThread = new ValidateThread(badFPS, perfectFPS);
+            validateThread.start();
+            validateThread.join();
+            return validateThread.getFPS();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        synchronized (mSurfaceLock) {
+            mSurfaceWasChanged = true;
+        }
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        // This method is always called at least once, after surfaceCreated.
+        synchronized (mSurfaceLock) {
+            mSurface = holder.getSurface();
+            // We only need to invalidate the surface for the compositor performance test so that
+            // it gets included in the composition process. For allocation performance we
+            // don't need to invalidate surface and this allows us to remove non-necessary
+            // surface invalidation from the test.
+            if (mDrawNameOnReady) {
+                invalidateSurface(true);
+            }
+            mSurfaceWasChanged = true;
+            mSurfaceLock.notify();
+        }
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        synchronized (mSurfaceLock) {
+            mSurface = null;
+            mSurfaceWasChanged = true;
+            mSurfaceLock.notify();
+        }
+    }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java b/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java
new file mode 100644
index 0000000..c716dae
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/MemoryAccessTask.java
@@ -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.
+ */
+package android.surfacecomposition;
+
+import android.util.Log;
+
+/**
+ * This task will simulate CPU activity by consuming memory bandwidth from the system.
+ * Note: On most system the CPU and GPU will share the same memory.
+ */
+public class MemoryAccessTask {
+    private final static String TAG = "MemoryAccessTask";
+    private final static int BUFFER_SIZE = 32 * 1024 * 1024;
+    private final static int BUFFER_STEP = 256;
+    private boolean mStopRequested;
+    private WorkThread mThread;
+    private final Object mLock = new Object();
+
+    public class WorkThread extends Thread {
+        public void run() {
+            byte[] memory = new byte[BUFFER_SIZE];
+            while (true) {
+                synchronized (mLock) {
+                    if (mStopRequested) {
+                        break;
+                    }
+                }
+                long result = 0;
+                for (int index = 0; index < BUFFER_SIZE; index += BUFFER_STEP) {
+                    result += ++memory[index];
+                }
+                Log.v(TAG, "Processing...:" + result);
+            }
+        }
+    }
+
+    public void start() {
+        if (mThread != null) {
+            throw new RuntimeException("Work thread is already started");
+        }
+        mStopRequested = false;
+        mThread = new WorkThread();
+        mThread.start();
+    }
+
+    public void stop() {
+        if (mThread != null) {
+            synchronized (mLock) {
+                mStopRequested = true;
+            }
+            try {
+                mThread.join();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
new file mode 100644
index 0000000..e3e1d34
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
@@ -0,0 +1,602 @@
+/*
+ * 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.surfacecomposition;
+
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.view.Display;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+/**
+ * This activity is designed to measure peformance scores of Android surfaces.
+ * It can work in two modes. In first mode functionality of this activity is
+ * invoked from Cts test (SurfaceCompositionTest). This activity can also be
+ * used in manual mode as a normal app. Different pixel formats are supported.
+ *
+ * measureCompositionScore(pixelFormat)
+ *   This test measures surface compositor performance which shows how many
+ *   surfaces of specific format surface compositor can combine without dropping
+ *   frames. We allow one dropped frame per half second.
+ *
+ * measureAllocationScore(pixelFormat)
+ *   This test measures surface allocation/deallocation performance. It shows
+ *   how many surface lifecycles (creation, destruction) can be done per second.
+ *
+ * In manual mode, which activated by pressing button 'Compositor speed' or
+ * 'Allocator speed', all possible pixel format are tested and combined result
+ * is displayed in text view. Additional system information such as memory
+ * status, display size and surface format is also displayed and regulary
+ * updated.
+ */
+public class SurfaceCompositionMeasuringActivity extends Activity implements OnClickListener {
+    private final static int MIN_NUMBER_OF_SURFACES = 15;
+    private final static int MAX_NUMBER_OF_SURFACES = 40;
+    private final static int WARM_UP_ALLOCATION_CYCLES = 2;
+    private final static int MEASURE_ALLOCATION_CYCLES = 5;
+    private final static int TEST_COMPOSITOR = 1;
+    private final static int TEST_ALLOCATION = 2;
+    private final static float MIN_REFRESH_RATE_SUPPORTED = 50.0f;
+
+    private final static DecimalFormat DOUBLE_FORMAT = new DecimalFormat("#.00");
+    // Possible selection in pixel format selector.
+    private final static int[] PIXEL_FORMATS = new int[] {
+            PixelFormat.TRANSLUCENT,
+            PixelFormat.TRANSPARENT,
+            PixelFormat.OPAQUE,
+            PixelFormat.RGBA_8888,
+            PixelFormat.RGBX_8888,
+            PixelFormat.RGB_888,
+            PixelFormat.RGB_565,
+    };
+
+
+    private List<CustomSurfaceView> mViews = new ArrayList<CustomSurfaceView>();
+    private Button mMeasureCompositionButton;
+    private Button mMeasureAllocationButton;
+    private Spinner mPixelFormatSelector;
+    private TextView mResultView;
+    private TextView mSystemInfoView;
+    private final Object mLockResumed = new Object();
+    private boolean mResumed;
+
+    // Drop one frame per half second.
+    // TODO(khmel)
+    // Add a feature flag and set the target FPS dependent on the target system as e.g.:
+    // 59FPS for MULTI_WINDOW and 54 otherwise (to satisfy the default lax Android requirements).
+    private double mRefreshRate;
+    private double mTargetFPS;
+
+    private int mWidth;
+    private int mHeight;
+
+    class CompositorScore {
+        double mSurfaces;
+        double mBitrate;
+
+        @Override
+        public String toString() {
+            return DOUBLE_FORMAT.format(mSurfaces) + " surfaces. " +
+                    "Bitrate: " + getReadableMemory((long)mBitrate) + "/s";
+        }
+    }
+
+    /**
+     * Measure performance score.
+     *
+     * @return biggest possible number of visible surfaces which surface
+     *         compositor can handle.
+     */
+    public CompositorScore measureCompositionScore(int pixelFormat) {
+        waitForActivityResumed();
+        //MemoryAccessTask memAccessTask = new MemoryAccessTask();
+        //memAccessTask.start();
+        // Destroy any active surface.
+        configureSurfacesAndWait(0, pixelFormat, false);
+        CompositorScore score = new CompositorScore();
+        score.mSurfaces = measureCompositionScore(new Measurement(0, 60.0),
+                new Measurement(mViews.size() + 1, 0.0f), pixelFormat);
+        // Assume 32 bits per pixel.
+        score.mBitrate = score.mSurfaces * mTargetFPS * mWidth * mHeight * 4.0;
+        //memAccessTask.stop();
+        return score;
+    }
+
+    static class AllocationScore {
+        double mMedian;
+        double mMin;
+        double mMax;
+
+        @Override
+        public String toString() {
+            return DOUBLE_FORMAT.format(mMedian) + " (min:" + DOUBLE_FORMAT.format(mMin) +
+                    ", max:" + DOUBLE_FORMAT.format(mMax) + ") surface allocations per second";
+        }
+    }
+
+    public AllocationScore measureAllocationScore(int pixelFormat) {
+        waitForActivityResumed();
+        AllocationScore score = new AllocationScore();
+        for (int i = 0; i < MEASURE_ALLOCATION_CYCLES + WARM_UP_ALLOCATION_CYCLES; ++i) {
+            long time1 = System.currentTimeMillis();
+            configureSurfacesAndWait(MIN_NUMBER_OF_SURFACES, pixelFormat, false);
+            acquireSurfacesCanvas();
+            long time2 = System.currentTimeMillis();
+            releaseSurfacesCanvas();
+            configureSurfacesAndWait(0, pixelFormat, false);
+            // Give SurfaceFlinger some time to rebuild the layer stack and release the buffers.
+            try {
+                Thread.sleep(500);
+            } catch(InterruptedException e) {
+                e.printStackTrace();
+            }
+            if (i < WARM_UP_ALLOCATION_CYCLES) {
+                // This is warm-up cycles, ignore result so far.
+                continue;
+            }
+            double speed = MIN_NUMBER_OF_SURFACES * 1000.0 / (time2 - time1);
+            score.mMedian += speed / MEASURE_ALLOCATION_CYCLES;
+            if (i == WARM_UP_ALLOCATION_CYCLES) {
+                score.mMin = speed;
+                score.mMax = speed;
+            } else {
+                score.mMin = Math.min(score.mMin, speed);
+                score.mMax = Math.max(score.mMax, speed);
+            }
+        }
+
+        return score;
+    }
+
+    @Override
+    public void onClick(View view) {
+        if (view == mMeasureCompositionButton) {
+            doTest(TEST_COMPOSITOR);
+        } else if (view == mMeasureAllocationButton) {
+            doTest(TEST_ALLOCATION);
+        }
+    }
+
+    private void doTest(final int test) {
+        enableControls(false);
+        final int pixelFormat = PIXEL_FORMATS[mPixelFormatSelector.getSelectedItemPosition()];
+        new Thread() {
+            public void run() {
+                final StringBuffer sb = new StringBuffer();
+                switch (test) {
+                    case TEST_COMPOSITOR: {
+                            sb.append("Compositor score:");
+                            CompositorScore score = measureCompositionScore(pixelFormat);
+                            sb.append("\n    " + getPixelFormatInfo(pixelFormat) + ":" +
+                                    score + ".");
+                        }
+                        break;
+                    case TEST_ALLOCATION: {
+                            sb.append("Allocation score:");
+                            AllocationScore score = measureAllocationScore(pixelFormat);
+                            sb.append("\n    " + getPixelFormatInfo(pixelFormat) + ":" +
+                                    score + ".");
+                        }
+                        break;
+                }
+                runOnUiThreadAndWait(new Runnable() {
+                    public void run() {
+                        mResultView.setText(sb.toString());
+                        enableControls(true);
+                        updateSystemInfo(pixelFormat);
+                    }
+                });
+            }
+        }.start();
+    }
+
+    /**
+     * Wait until activity is resumed.
+     */
+    public void waitForActivityResumed() {
+        synchronized (mLockResumed) {
+            if (!mResumed) {
+                try {
+                    mLockResumed.wait(10000);
+                } catch (InterruptedException e) {
+                }
+            }
+            if (!mResumed) {
+                throw new RuntimeException("Activity was not resumed");
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        detectRefreshRate();
+
+        // To layouts in parent. First contains list of Surfaces and second
+        // controls. Controls stay on top.
+        RelativeLayout rootLayout = new RelativeLayout(this);
+        rootLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        CustomLayout layout = new CustomLayout(this);
+        layout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        Rect rect = new Rect();
+        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+        mWidth = rect.right;
+        mHeight = rect.bottom;
+        long maxMemoryPerSurface = roundToNextPowerOf2(mWidth) * roundToNextPowerOf2(mHeight) * 4;
+        // Use 75% of available memory.
+        int surfaceCnt = (int)((getMemoryInfo().availMem * 3) / (4 * maxMemoryPerSurface));
+        if (surfaceCnt < MIN_NUMBER_OF_SURFACES) {
+            throw new RuntimeException("Not enough memory to allocate " +
+                    MIN_NUMBER_OF_SURFACES + " surfaces.");
+        }
+        if (surfaceCnt > MAX_NUMBER_OF_SURFACES) {
+            surfaceCnt = MAX_NUMBER_OF_SURFACES;
+        }
+
+        LinearLayout controlLayout = new LinearLayout(this);
+        controlLayout.setOrientation(LinearLayout.VERTICAL);
+        controlLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        mMeasureCompositionButton = createButton("Compositor speed.", controlLayout);
+        mMeasureAllocationButton = createButton("Allocation speed", controlLayout);
+
+        String[] pixelFomats = new String[PIXEL_FORMATS.length];
+        for (int i = 0; i < pixelFomats.length; ++i) {
+            pixelFomats[i] = getPixelFormatInfo(PIXEL_FORMATS[i]);
+        }
+        mPixelFormatSelector = new Spinner(this);
+        ArrayAdapter<String> pixelFormatSelectorAdapter =
+                new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, pixelFomats);
+        pixelFormatSelectorAdapter.setDropDownViewResource(
+                android.R.layout.simple_spinner_dropdown_item);
+        mPixelFormatSelector.setAdapter(pixelFormatSelectorAdapter);
+        mPixelFormatSelector.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        controlLayout.addView(mPixelFormatSelector);
+
+        mResultView = new TextView(this);
+        mResultView.setBackgroundColor(0);
+        mResultView.setText("Press button to start test.");
+        mResultView.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        controlLayout.addView(mResultView);
+
+        mSystemInfoView = new TextView(this);
+        mSystemInfoView.setBackgroundColor(0);
+        mSystemInfoView.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        controlLayout.addView(mSystemInfoView);
+
+        for (int i = 0; i < surfaceCnt; ++i) {
+            CustomSurfaceView view = new CustomSurfaceView(this, "Surface:" + i);
+            // Create all surfaces overlapped in order to prevent SurfaceFlinger
+            // to filter out surfaces by optimization in case surface is opaque.
+            // In case surface is transparent it will be drawn anyway. Note that first
+            // surface covers whole screen and must stand below other surfaces. Z order of
+            // layers is not predictable and there is only one way to force first
+            // layer to be below others is to mark it as media and all other layers
+            // to mark as media overlay.
+            if (i == 0) {
+                view.setLayoutParams(new CustomLayout.LayoutParams(0, 0, mWidth, mHeight));
+                view.setZOrderMediaOverlay(false);
+            } else {
+                // Z order of other layers is not predefined so make offset on x and reverse
+                // offset on y to make sure that surface is visible in any layout.
+                int x = i;
+                int y = (surfaceCnt - i);
+                view.setLayoutParams(new CustomLayout.LayoutParams(x, y, x + mWidth, y + mHeight));
+                view.setZOrderMediaOverlay(true);
+            }
+            view.setVisibility(View.INVISIBLE);
+            layout.addView(view);
+            mViews.add(view);
+        }
+
+        rootLayout.addView(layout);
+        rootLayout.addView(controlLayout);
+
+        setContentView(rootLayout);
+    }
+
+    private Button createButton(String caption, LinearLayout layout) {
+        Button button = new Button(this);
+        button.setText(caption);
+        button.setLayoutParams(new LinearLayout.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                ViewGroup.LayoutParams.WRAP_CONTENT));
+        button.setOnClickListener(this);
+        layout.addView(button);
+        return button;
+    }
+
+    private void enableControls(boolean enabled) {
+        mMeasureCompositionButton.setEnabled(enabled);
+        mMeasureAllocationButton.setEnabled(enabled);
+        mPixelFormatSelector.setEnabled(enabled);
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        updateSystemInfo(PixelFormat.UNKNOWN);
+
+        synchronized (mLockResumed) {
+            mResumed = true;
+            mLockResumed.notifyAll();
+        }
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+
+        synchronized (mLockResumed) {
+            mResumed = false;
+        }
+    }
+
+    class Measurement {
+        Measurement(int surfaceCnt, double fps) {
+            mSurfaceCnt = surfaceCnt;
+            mFPS = fps;
+        }
+
+        public final int mSurfaceCnt;
+        public final double mFPS;
+    }
+
+    private double measureCompositionScore(Measurement ok, Measurement fail, int pixelFormat) {
+        if (ok.mSurfaceCnt + 1 == fail.mSurfaceCnt) {
+            // Interpolate result.
+            double fraction = (mTargetFPS - fail.mFPS) / (ok.mFPS - fail.mFPS);
+            return ok.mSurfaceCnt + fraction;
+        }
+
+        int medianSurfaceCnt = (ok.mSurfaceCnt + fail.mSurfaceCnt) / 2;
+        Measurement median = new Measurement(medianSurfaceCnt,
+                measureFPS(medianSurfaceCnt, pixelFormat));
+
+        if (median.mFPS >= mTargetFPS) {
+            return measureCompositionScore(median, fail, pixelFormat);
+        } else {
+            return measureCompositionScore(ok, median, pixelFormat);
+        }
+    }
+
+    private double measureFPS(int surfaceCnt, int pixelFormat) {
+        configureSurfacesAndWait(surfaceCnt, pixelFormat, true);
+        // At least one view is visible and it is enough to update only
+        // one overlapped surface in order to force SurfaceFlinger to send
+        // all surfaces to compositor.
+        double fps = mViews.get(0).measureFPS(mRefreshRate * 0.8, mRefreshRate * 0.999);
+
+        // Make sure that surface configuration was not changed.
+        validateSurfacesNotChanged();
+
+        return fps;
+    }
+
+    private void waitForSurfacesConfigured(final int pixelFormat) {
+        for (int i = 0; i < mViews.size(); ++i) {
+            CustomSurfaceView view = mViews.get(i);
+            if (view.getVisibility() == View.VISIBLE) {
+                view.waitForSurfaceReady();
+            } else {
+                view.waitForSurfaceDestroyed();
+            }
+        }
+        runOnUiThreadAndWait(new Runnable() {
+            @Override
+            public void run() {
+                updateSystemInfo(pixelFormat);
+            }
+        });
+    }
+
+    private void validateSurfacesNotChanged() {
+        for (int i = 0; i < mViews.size(); ++i) {
+            CustomSurfaceView view = mViews.get(i);
+            view.validateSurfaceNotChanged();
+        }
+    }
+
+    private void configureSurfaces(int surfaceCnt, int pixelFormat, boolean invalidate) {
+        for (int i = 0; i < mViews.size(); ++i) {
+            CustomSurfaceView view = mViews.get(i);
+            if (i < surfaceCnt) {
+                view.setMode(pixelFormat, invalidate);
+                view.setVisibility(View.VISIBLE);
+            } else {
+                view.setVisibility(View.INVISIBLE);
+            }
+        }
+    }
+
+    private void configureSurfacesAndWait(final int surfaceCnt, final int pixelFormat,
+            final boolean invalidate) {
+        runOnUiThreadAndWait(new Runnable() {
+            @Override
+            public void run() {
+                configureSurfaces(surfaceCnt, pixelFormat, invalidate);
+            }
+        });
+        waitForSurfacesConfigured(pixelFormat);
+    }
+
+    private void acquireSurfacesCanvas() {
+        for (int i = 0; i < mViews.size(); ++i) {
+            CustomSurfaceView view = mViews.get(i);
+            view.acquireCanvas();
+        }
+    }
+
+    private void releaseSurfacesCanvas() {
+        for (int i = 0; i < mViews.size(); ++i) {
+            CustomSurfaceView view = mViews.get(i);
+            view.releaseCanvas();
+        }
+    }
+
+    private static String getReadableMemory(long bytes) {
+        long unit = 1024;
+        if (bytes < unit) {
+            return bytes + " B";
+        }
+        int exp = (int) (Math.log(bytes) / Math.log(unit));
+        return String.format("%.1f %sB", bytes / Math.pow(unit, exp),
+                "KMGTPE".charAt(exp-1));
+    }
+
+    private MemoryInfo getMemoryInfo() {
+        ActivityManager activityManager = (ActivityManager)
+                getSystemService(ACTIVITY_SERVICE);
+        MemoryInfo memInfo = new MemoryInfo();
+        activityManager.getMemoryInfo(memInfo);
+        return memInfo;
+    }
+
+    private void updateSystemInfo(int pixelFormat) {
+        int visibleCnt = 0;
+        for (int i = 0; i < mViews.size(); ++i) {
+            if (mViews.get(i).getVisibility() == View.VISIBLE) {
+                ++visibleCnt;
+            }
+        }
+
+        MemoryInfo memInfo = getMemoryInfo();
+        String info = "Available " +
+                getReadableMemory(memInfo.availMem) + " from " +
+                getReadableMemory(memInfo.totalMem) + ".\nVisible " +
+                visibleCnt + " from " + mViews.size() + " " +
+                getPixelFormatInfo(pixelFormat) + " surfaces.\n" +
+                "View size: " + mWidth + "x" + mHeight +
+                ". Refresh rate: " + DOUBLE_FORMAT.format(mRefreshRate) + ".";
+        mSystemInfoView.setText(info);
+    }
+
+    private void detectRefreshRate() {
+        WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
+        mRefreshRate = wm.getDefaultDisplay().getRefreshRate();
+        if (mRefreshRate < MIN_REFRESH_RATE_SUPPORTED)
+            throw new RuntimeException("Unsupported display refresh rate: " + mRefreshRate);
+        mTargetFPS = mRefreshRate - 2.0f;
+    }
+
+    private int roundToNextPowerOf2(int value) {
+        --value;
+        value |= value >> 1;
+        value |= value >> 2;
+        value |= value >> 4;
+        value |= value >> 8;
+        value |= value >> 16;
+        return value + 1;
+    }
+
+    public static String getPixelFormatInfo(int pixelFormat) {
+        switch (pixelFormat) {
+        case PixelFormat.TRANSLUCENT:
+            return "TRANSLUCENT";
+        case PixelFormat.TRANSPARENT:
+            return "TRANSPARENT";
+        case PixelFormat.OPAQUE:
+            return "OPAQUE";
+        case PixelFormat.RGBA_8888:
+            return "RGBA_8888";
+        case PixelFormat.RGBX_8888:
+            return "RGBX_8888";
+        case PixelFormat.RGB_888:
+            return "RGB_888";
+        case PixelFormat.RGB_565:
+            return "RGB_565";
+        default:
+            return "PIX.FORMAT:" + pixelFormat;
+        }
+    }
+
+    /**
+     * A helper that executes a task in the UI thread and waits for its completion.
+     *
+     * @param task - task to execute.
+     */
+    private void runOnUiThreadAndWait(Runnable task) {
+        new UIExecutor(task);
+    }
+
+    class UIExecutor implements Runnable {
+        private final Object mLock = new Object();
+        private Runnable mTask;
+        private boolean mDone = false;
+
+        UIExecutor(Runnable task) {
+            mTask = task;
+            mDone = false;
+            runOnUiThread(this);
+            synchronized (mLock) {
+                while (!mDone) {
+                    try {
+                        mLock.wait();
+                    } catch (InterruptedException e) {
+                        e.printStackTrace();
+                    }
+                }
+            }
+        }
+
+        public void run() {
+            mTask.run();
+            synchronized (mLock) {
+                mDone = true;
+                mLock.notify();
+            }
+        }
+    }
+}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.java
new file mode 100644
index 0000000..6e9e739
--- /dev/null
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionTest.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.surfacecomposition;
+
+import android.graphics.PixelFormat;
+import android.surfacecomposition.SurfaceCompositionMeasuringActivity.AllocationScore;
+import android.surfacecomposition.SurfaceCompositionMeasuringActivity.CompositorScore;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+public class SurfaceCompositionTest extends
+        ActivityInstrumentationTestCase2<SurfaceCompositionMeasuringActivity> {
+    private final static String TAG = "SurfaceCompositionTest";
+
+    // Pass threshold for major pixel formats.
+    private final static int[] TEST_PIXEL_FORMATS = new int[] {
+        PixelFormat.TRANSLUCENT,
+        PixelFormat.OPAQUE,
+    };
+
+    // Based on Nexus 9 performance which is usually < 9.0.
+    private final static double[] MIN_ACCEPTED_COMPOSITION_SCORE = new double[] {
+        8.0,
+        8.0,
+    };
+
+    // Based on Nexus 6 performance which is usually < 28.0.
+    private final static double[] MIN_ACCEPTED_ALLOCATION_SCORE = new double[] {
+        20.0,
+        20.0,
+    };
+
+    public SurfaceCompositionTest() {
+        super(SurfaceCompositionMeasuringActivity.class);
+    }
+
+    private void testRestoreContexts() {
+    }
+
+    @SmallTest
+    public void testSurfaceCompositionPerformance() {
+        for (int i = 0; i < TEST_PIXEL_FORMATS.length; ++i) {
+            int pixelFormat = TEST_PIXEL_FORMATS[i];
+            String formatName = SurfaceCompositionMeasuringActivity.getPixelFormatInfo(pixelFormat);
+            CompositorScore score = getActivity().measureCompositionScore(pixelFormat);
+            Log.i(TAG, "testSurfaceCompositionPerformance(" + formatName + ") = " + score);
+            assertTrue("Device does not support surface(" + formatName + ") composition " +
+                    "performance score. " + score.mSurfaces + " < " +
+                    MIN_ACCEPTED_COMPOSITION_SCORE[i] + ".",
+                    score.mSurfaces >= MIN_ACCEPTED_COMPOSITION_SCORE[i]);
+        }
+    }
+
+    @SmallTest
+    public void testSurfaceAllocationPerformance() {
+        for (int i = 0; i < TEST_PIXEL_FORMATS.length; ++i) {
+            int pixelFormat = TEST_PIXEL_FORMATS[i];
+            String formatName = SurfaceCompositionMeasuringActivity.getPixelFormatInfo(pixelFormat);
+            AllocationScore score = getActivity().measureAllocationScore(pixelFormat);
+            Log.i(TAG, "testSurfaceAllocationPerformance(" + formatName + ") = " + score);
+            assertTrue("Device does not support surface(" + formatName + ") allocation " +
+                    "performance score. " + score.mMedian + " < " +
+                    MIN_ACCEPTED_ALLOCATION_SCORE[i] + ".",
+                    score.mMedian >= MIN_ACCEPTED_ALLOCATION_SCORE[i]);
+        }
+    }
+}
diff --git a/tests/TileBenchmark/AndroidManifest.xml b/tests/TileBenchmark/AndroidManifest.xml
deleted file mode 100644
index c569ff4..0000000
--- a/tests/TileBenchmark/AndroidManifest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-      android:versionCode="1"
-      android:versionName="1.0" package="com.test.tilebenchmark">
-    <uses-permission android:name="android.permission.INTERNET"/>
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-    <application android:icon="@drawable/icon"
-                 android:label="@string/app_name"
-                 android:hardwareAccelerated="true">
-        <activity android:name=".ProfileActivity"
-                  android:label="@string/profile_activity"
-                  android:theme="@android:style/Theme.Holo.NoActionBar">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-        <activity android:name=".PlaybackActivity"
-                  android:label="@string/playback_activity"
-                  android:theme="@android:style/Theme.Holo.NoActionBar">
-        </activity>
-        <uses-library android:name="android.test.runner" />
-    </application>
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-                     android:targetPackage="com.test.tilebenchmark"
-                     android:label="Tests for WebView Tiles."/>
-</manifest>
diff --git a/tests/TileBenchmark/res/drawable-hdpi/icon.png b/tests/TileBenchmark/res/drawable-hdpi/icon.png
deleted file mode 100644
index 8074c4c..0000000
--- a/tests/TileBenchmark/res/drawable-hdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/tests/TileBenchmark/res/drawable-ldpi/icon.png b/tests/TileBenchmark/res/drawable-ldpi/icon.png
deleted file mode 100644
index 1095584..0000000
--- a/tests/TileBenchmark/res/drawable-ldpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/tests/TileBenchmark/res/drawable-mdpi/icon.png b/tests/TileBenchmark/res/drawable-mdpi/icon.png
deleted file mode 100644
index a07c69f..0000000
--- a/tests/TileBenchmark/res/drawable-mdpi/icon.png
+++ /dev/null
Binary files differ
diff --git a/tests/TileBenchmark/res/layout/main.xml b/tests/TileBenchmark/res/layout/main.xml
deleted file mode 100644
index 1b39d5d..0000000
--- a/tests/TileBenchmark/res/layout/main.xml
+++ /dev/null
@@ -1,72 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-    <HorizontalScrollView
-        android:id="@+id/horizontalScrollView"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        >
-        <LinearLayout
-            android:id="@+id/top"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            >
-            <Spinner
-                android:id="@+id/movement"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:prompt="@string/movement_method"
-                />
-            <Spinner
-                android:id="@+id/velocity"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:gravity="center_horizontal"
-                android:prompt="@string/desired_scroll_velocity"
-                />
-            <ToggleButton
-                android:id="@+id/capture"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textOn="@string/capture_stop"
-                android:textOff="@string/capture_start"
-                />
-            <EditText
-                android:id="@+id/url"
-                android:layout_width="400dp"
-                android:layout_height="wrap_content"
-                android:inputType="textUri"
-                android:imeOptions="actionGo|flagNoExtractUi"
-                android:layout_weight="1"
-                />
-            <Button
-                android:id="@+id/inspect"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:text="@string/inspect_log"
-                />
-        </LinearLayout>
-    </HorizontalScrollView>
-    <com.test.tilebenchmark.ProfiledWebView
-        android:id="@+id/web"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-</LinearLayout>
diff --git a/tests/TileBenchmark/res/layout/playback.xml b/tests/TileBenchmark/res/layout/playback.xml
deleted file mode 100644
index aa1c8a4..0000000
--- a/tests/TileBenchmark/res/layout/playback.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    >
-    <LinearLayout
-        android:id="@+id/top"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        >
-        <Button
-            android:id="@+id/backward"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/backward"
-            />
-        <TextView
-            android:id="@+id/frame_display"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:gravity="center_horizontal"
-            android:textAppearance="?android:attr/textAppearanceLarge"
-            android:layout_weight="1"
-            />
-        <Button
-            android:id="@+id/forward"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:text="@string/forward"
-            />
-        <SeekBar
-            android:id="@+id/seek_bar"
-            android:layout_width="0dip"
-            android:layout_height="wrap_content"
-            android:layout_weight="10"
-            />
-    </LinearLayout>
-    <com.test.tilebenchmark.PlaybackView
-        android:id="@+id/playback"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        />
-</LinearLayout>
diff --git a/tests/TileBenchmark/res/values/colors.xml b/tests/TileBenchmark/res/values/colors.xml
deleted file mode 100644
index dbb8e72..0000000
--- a/tests/TileBenchmark/res/values/colors.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <!-- The color of tiles with valid textures -->
-    <color name="ready_tile">#ff4ac230</color>
-    <!-- The color of tiles with stale / invalid textures -->
-    <color name="unready_tile">#ff744400</color>
-    <!-- Viewport overlay in playback -->
-    <color name="view">#50000050</color>
-    <!-- Invalidated region overlay in playback - start color -->
-    <color name="inval_region_start">#80ff0000</color>
-    <!-- Invalidated region overlay in playback - stop color-->
-    <color name="inval_region_stop">#80ffffff</color>
-
-    <!-- Background color for not testing -->
-    <color name="background_not_testing">#ff000000</color>
-    <!-- Background color for during testing -->
-    <color name="background_start_testing">#ff400000</color>
-    <!-- Background color for testing complete -->
-    <color name="background_stop_testing">#ff004000</color>
-</resources>
diff --git a/tests/TileBenchmark/res/values/strings.xml b/tests/TileBenchmark/res/values/strings.xml
deleted file mode 100644
index 6c7055b..0000000
--- a/tests/TileBenchmark/res/values/strings.xml
+++ /dev/null
@@ -1,107 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<resources>
-    <!-- Button, steps back a single frame [CHAR LIMIT=15] -->
-    <string name="backward">Backward</string>
-    <!-- Button, steps forward a single frame [CHAR LIMIT=15] -->
-    <string name="forward">Forward</string>
-    <!-- The name of the application [CHAR LIMIT=20] -->
-    <string name="app_name">TileBenchmark</string>
-    <!-- name of the auto-scroller / tile logger activity [CHAR LIMIT=100] -->
-    <string name="profile_activity">Webview Profiler</string>
-    <!-- name of the tile log playback activity [CHAR LIMIT=100] -->
-    <string name="playback_activity">Webview Tile Playback</string>
-    <!-- Button, loads another tile log [CHAR LIMIT=30] -->
-    <string name="loadbutton">Load</string>
-    <!-- Button, opens the playback activity [CHAR LIMIT=20] -->
-    <string name="inspect_log">Inspect Log</string>
-    <!-- ToggleButton label when pressing starts capture [CHAR LIMIT=15] -->
-    <string name="capture_start">Start Capture</string>
-    <!-- ToggleButton label when pressing stops capture [CHAR LIMIT=15] -->
-    <string name="capture_stop">Stop Capture</string>
-    <!-- The speed of auto-scrolling [CHAR LIMIT=30] -->
-    <string name="desired_scroll_velocity">Choose Scroll Velocity</string>
-    <!-- Pixels moved per frame [CHAR LIMIT=10] -->
-    <string-array name="velocity_array">
-        <item>1</item>
-        <item>25</item>
-        <item>50</item>
-        <item>100</item>
-        <item>200</item>
-        <item>400</item>
-    </string-array>
-    <!-- Drop down menu for selecting scrolling vs manual navigation for
-    capturing [CHAR LIMIT=15] -->
-    <string name="movement_method">Movement Method</string>
-    <!-- Drop down menu entry - automatically scroll to the end of the page
-    with scrollBy() [CHAR LIMIT=15] -->
-    <string name="movement_auto_scroll">Auto-scroll</string>
-    <!-- Drop down menu entry - automatically record for a set time before
-    stopping [CHAR LIMIT=15] -->
-    <string name="movement_timed">Timed</string>
-    <!-- Drop down menu entry - manually navigate the page(s), hit 'capture'
-    button [CHAR LIMIT=15] -->
-    <string name="movement_manual">Manual</string>
-
-    <!-- Error popup indicating log data couldn't be loaded [CHAR LIMIT=60] -->
-    <string name="error_no_data">Error: log data could not be loaded.</string>
-
-    <!-- 25th percentile - 25% of frames fall below this value [CHAR LIMIT=12]
-    -->
-    <string name="percentile_25">25%ile</string>
-    <!-- 50th percentile - 50% of frames fall below this value (aka median)
-    [CHAR LIMIT=12] -->
-    <string name="percentile_50">median</string>
-    <!-- 75th percentile - 75% of frames fall below this value [CHAR LIMIT=12]
-    -->
-    <string name="percentile_75">75%ile</string>
-    <!-- standard deviation [CHAR LIMIT=12] -->
-    <string name="std_dev">StdDev</string>
-    <!-- mean [CHAR LIMIT=12] -->
-    <string name="mean">mean</string>
-
-
-
-    <!-- Frame rate [CHAR LIMIT=15] -->
-    <string name="frames_per_second">Frames/sec</string>
-    <!-- Portion of viewport covered by good tiles [CHAR LIMIT=15] -->
-    <string name="viewport_coverage">Coverage</string>
-    <!-- Milliseconds taken to inval, and re-render the page [CHAR LIMIT=15] -->
-    <string name="render_millis">RenderMillis</string>
-    <!-- Animation Framerate [CHAR LIMIT=15] -->
-    <string name="animation_framerate">AnimFramerate</string>
-    <!-- Format string for stat value overlay [CHAR LIMIT=15] -->
-    <string name="format_stat">%4.4f</string>
-
-    <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
-    <string name="format_view_pos">View:(%1$d,%2$d)-(%3$d,%4$d)</string>
-    <!-- Format string for viewport position value overlay [CHAR LIMIT=25] -->
-    <string name="format_inval_pos">Inval:(%1$d,%2$d)-(%3$d,%4$d)</string>
-
-    <!-- Format string for displaying aggregate stats+values (nr of valid tiles,
-    etc.) [CHAR LIMIT=20] -->
-    <string name="format_stat_name">%1$-20s %2$3d</string>
-    <!-- Text hovering over canvas, number of tiles ready [CHAR LIMIT=15] -->
-    <string name="ready_tiles">Ready Tiles</string>
-    <!-- Text hovering over canvas, number tiles not ready [CHAR LIMIT=15] -->
-    <string name="unready_tiles">Unready Tiles</string>
-    <!-- Text hovering over canvas, number of tiles that haven't been
-    allocated to a place on the page [CHAR LIMIT=15] -->
-    <string name="unplaced_tiles">Unplaced Tiles</string>
-    <!-- Text hovering over canvas, number of invalidated regions this frame
-    [CHAR LIMIT=15] -->
-    <string name="number_invalidates">Invalidates</string>
-</resources>
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index ce9db3d..24df85b 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -9,14 +9,19 @@
 # use appcompat/support lib from the tree, so improvements/
 # regressions are reflected in test data
 LOCAL_RESOURCE_DIR := \
-    frameworks/support/v7/appcompat/res
+    $(LOCAL_PATH)/res \
+    frameworks/support/v7/appcompat/res \
+    frameworks/support/v7/cardview/res
 
 LOCAL_AAPT_FLAGS := \
-    --extra-packages android.support.v7.appcompat
+    --auto-add-overlay \
+    --extra-packages android.support.v7.appcompat \
+    --extra-packages android.support.v7.cardview
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-v4 \
-    android-support-v7-appcompat
+    android-support-v7-appcompat \
+    android-support-v7-cardview
 
 LOCAL_PACKAGE_NAME := UiBench
 
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index b19e109..9b3d186 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -14,11 +14,13 @@
   ~ limitations under the License
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.test.uibench">
+    xmlns:tools="http://schemas.android.com/tools"
+    package="com.android.test.uibench">
 
     <application
         android:allowBackup="false"
-        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+        android:theme="@style/Theme.AppCompat.Light.DarkActionBar"
+        tools:ignore="MissingApplicationIcon">
         <uses-library android:name="android.test.runner" />
 
         <!-- Root navigation activity -->
@@ -32,10 +34,104 @@
             </intent-filter>
         </activity>
 
-        <!-- Tests -->
+        <!-- General -->
+        <activity
+            android:name=".DialogListActivity"
+            android:label="General/Dialog List" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".GlTextureViewActivity"
+            android:label="General/GL TextureView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".FullscreenOverdrawActivity"
+            android:label="General/Fullscreen Overdraw" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".InvalidateActivity"
+            android:label="General/Invalidate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TrivialAnimationActivity"
+            android:label="General/Trivial Animation" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
         <activity
             android:name=".TrivialListActivity"
-            android:label="Microbenchmarks/Trivial ListActivity" >
+            android:label="General/Trivial ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Rendering -->
+        <activity
+            android:name=".BitmapUploadActivity"
+            android:label="Rendering/Bitmap Upload" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".ShadowGridActivity"
+            android:label="Rendering/Shadow Grid" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Inflation -->
+        <activity
+            android:name=".InflatingListActivity"
+            android:label="Inflation/Inflating ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+
+        <!-- Text -->
+        <activity
+            android:name=".EditTextTypeActivity"
+            android:label="Text/EditText Typing" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TextCacheLowHitrateActivity"
+            android:label="Text/Layout Cache Low Hitrate" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".TextCacheHighHitrateActivity"
+            android:label="Text/Layout Cache High Hitrate" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="com.android.test.uibench.TEST" />
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
index bf0ed11..deecbb6 100644
--- a/tests/UiBench/build.gradle
+++ b/tests/UiBench/build.gradle
@@ -34,4 +34,5 @@
     // Dependencies enumerated specifically for platform-independent / reproducible builds.
     compile 'com.android.support:support-v4:23.0.0'
     compile 'com.android.support:appcompat-v7:23.0.0'
+    compile 'com.android.support:cardview-v7:23.0.0'
 }
diff --git a/tests/UiBench/res/drawable-nodpi/large_photo.jpg b/tests/UiBench/res/drawable-nodpi/large_photo.jpg
new file mode 100644
index 0000000..e23dbb0
--- /dev/null
+++ b/tests/UiBench/res/drawable-nodpi/large_photo.jpg
Binary files differ
diff --git a/tests/UiBench/res/layout/activity_bitmap_upload.xml b/tests/UiBench/res/layout/activity_bitmap_upload.xml
new file mode 100644
index 0000000..70faa07
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_bitmap_upload.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/upload_root"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:padding="10dp"
+    android:clipToPadding="false">
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1">
+        <view class="com.android.test.uibench.BitmapUploadActivity$UploadView"
+            android:id="@+id/upload_view"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </android.support.v7.widget.CardView>
+
+    <android.support.v4.widget.Space
+        android:layout_height="10dp"
+        android:layout_width="match_parent" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+    <android.support.v4.widget.Space
+        android:layout_height="10dp"
+        android:layout_width="match_parent" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/activity_invalidate.xml b/tests/UiBench/res/layout/activity_invalidate.xml
new file mode 100644
index 0000000..34bcca9
--- /dev/null
+++ b/tests/UiBench/res/layout/activity_invalidate.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/invalidate_root"
+    android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+    <include layout="@layout/invalidate_row"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/card_row.xml b/tests/UiBench/res/layout/card_row.xml
new file mode 100644
index 0000000..215f9df
--- /dev/null
+++ b/tests/UiBench/res/layout/card_row.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="100dp"
+    android:paddingStart="10dp"
+    android:paddingEnd="10dp"
+    android:paddingTop="5dp"
+    android:paddingBottom="5dp"
+    android:clipToPadding="false"
+    android:background="@null">
+    <android.support.v7.widget.CardView
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1">
+        <TextView
+            android:id="@+id/card_text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"/>
+    </android.support.v7.widget.CardView>
+
+    <android.support.v4.widget.Space
+        android:layout_height="match_parent"
+        android:layout_width="10dp" />
+
+    <android.support.v7.widget.CardView
+        android:layout_width="0dp"
+        android:layout_height="match_parent"
+        android:layout_weight="1" />
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/res/layout/invalidate_row.xml b/tests/UiBench/res/layout/invalidate_row.xml
new file mode 100644
index 0000000..9feefde
--- /dev/null
+++ b/tests/UiBench/res/layout/invalidate_row.xml
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="horizontal"
+    android:layout_width="match_parent"
+    android:layout_height="0dp"
+    android:layout_weight="1">
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+    <view class="com.android.test.uibench.InvalidateActivity$ColorView"
+        android:layout_weight="1"
+        android:layout_width="0dp"
+        android:layout_height="match_parent"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java b/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java
new file mode 100644
index 0000000..e2bf897
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/BitmapUploadActivity.java
@@ -0,0 +1,96 @@
+/*
+ * 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.View;
+
+public class BitmapUploadActivity extends AppCompatActivity {
+    public static class UploadView extends View {
+        private int mColorValue;
+        private Bitmap mBitmap;
+        private final DisplayMetrics mMetrics = new DisplayMetrics();
+        private final Rect mRect = new Rect();
+
+        public UploadView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        @SuppressWarnings("unused")
+        public void setColorValue(int colorValue) {
+            if (colorValue == mColorValue) return;
+
+            mColorValue = colorValue;
+
+            // modify the bitmap's color to ensure it's uploaded to the GPU
+            mBitmap.eraseColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+            invalidate();
+        }
+
+        @Override
+        protected void onAttachedToWindow() {
+            super.onAttachedToWindow();
+
+            getDisplay().getMetrics(mMetrics);
+            int minDisplayDimen = Math.min(mMetrics.widthPixels, mMetrics.heightPixels);
+            int bitmapSize = Math.min((int) (minDisplayDimen * 0.75), 720);
+            if (mBitmap == null
+                    || mBitmap.getWidth() != bitmapSize
+                    || mBitmap.getHeight() != bitmapSize) {
+                mBitmap = Bitmap.createBitmap(bitmapSize, bitmapSize, Bitmap.Config.ARGB_8888);
+            }
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            if (mBitmap != null) {
+                mRect.set(0, 0, getWidth(), getHeight());
+                canvas.drawBitmap(mBitmap, null, mRect, null);
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_bitmap_upload);
+
+        // animate color to force bitmap uploads
+        UploadView uploadView = (UploadView) findViewById(R.id.upload_view);
+        ObjectAnimator colorValueAnimator = ObjectAnimator.ofInt(uploadView, "colorValue", 0, 255);
+        colorValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        colorValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        colorValueAnimator.start();
+
+        // animate scene root to guarantee there's a minimum amount of GPU rendering work
+        View uploadRoot = findViewById(R.id.upload_root);
+        ObjectAnimator yAnimator = ObjectAnimator.ofFloat(uploadRoot, "translationY", 0, 100);
+        yAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        yAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        yAnimator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java b/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
new file mode 100644
index 0000000..40ec453
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/CompatListActivity.java
@@ -0,0 +1,39 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ListAdapter;
+
+public abstract class CompatListActivity extends AppCompatActivity {
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment();
+            listFragment.setListAdapter(createListAdapter());
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+
+    protected abstract ListAdapter createListAdapter();
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
new file mode 100644
index 0000000..fe712d5
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/DialogListActivity.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.uibench;
+
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+public class DialogListActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ListView listView = new ListView(this);
+        listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList()));
+
+        AlertDialog.Builder builder = new AlertDialog.Builder(this);
+        builder.setTitle("Dialog");
+        builder.setView(listView);
+        builder.create().show();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java b/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java
new file mode 100644
index 0000000..08ab510
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/EditTextTypeActivity.java
@@ -0,0 +1,110 @@
+/*
+ * 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.test.uibench;
+
+import android.app.Instrumentation;
+import android.os.Bundle;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.support.v7.app.AppCompatActivity;
+import android.view.KeyEvent;
+import android.widget.EditText;
+
+import java.util.concurrent.Semaphore;
+
+/**
+ * Note: currently incomplete, complexity of input continuously grows, instead of looping
+ * over a stable amount of work.
+ *
+ * Simulates typing continuously into an EditText.
+ */
+public class EditTextTypeActivity extends AppCompatActivity {
+    Thread mThread;
+
+    private static String sSeedText = "";
+    static {
+        final int count = 100;
+        final String string = "hello ";
+
+        StringBuilder builder = new StringBuilder(count * string.length());
+        for (int i = 0; i < count; i++) {
+            builder.append(string);
+        }
+        sSeedText = builder.toString();
+    }
+
+    final Object mLock = new Object();
+    boolean mShouldStop = false;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        EditText editText = new EditText(this);
+        editText.setText(sSeedText);
+        setContentView(editText);
+
+        final Instrumentation instrumentation = new Instrumentation();
+        final Semaphore sem = new Semaphore(0);
+        MessageQueue.IdleHandler handler = new MessageQueue.IdleHandler() {
+            @Override
+            public boolean queueIdle() {
+                // TODO: consider other signaling approaches
+                sem.release();
+                return true;
+            }
+        };
+        Looper.myQueue().addIdleHandler(handler);
+        synchronized (mLock) {
+            mShouldStop = false;
+        }
+        mThread = new Thread(new Runnable() {
+            int codes[] = { KeyEvent.KEYCODE_H, KeyEvent.KEYCODE_E, KeyEvent.KEYCODE_L,
+                    KeyEvent.KEYCODE_L, KeyEvent.KEYCODE_O, KeyEvent.KEYCODE_SPACE };
+            int i = 0;
+            @Override
+            public void run() {
+                while (true) {
+                    try {
+                        sem.acquire();
+                    } catch (InterruptedException e) {
+                        // TODO, maybe
+                    }
+                    int code = codes[i % codes.length];
+                    if (i % 100 == 99) code = KeyEvent.KEYCODE_ENTER;
+
+                    synchronized (mLock) {
+                        if (mShouldStop) break;
+                    }
+
+                    // TODO: bit of a race here, since the event can arrive after pause/stop.
+                    // (Can't synchronize on key send, since it's synchronous.)
+                    instrumentation.sendKeyDownUpSync(code);
+                    i++;
+                }
+            }
+        });
+        mThread.start();
+    }
+
+    @Override
+    protected void onPause() {
+        synchronized (mLock) {
+            mShouldStop = true;
+        }
+        super.onPause();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java b/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java
new file mode 100644
index 0000000..f1ecc56
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/FullscreenOverdrawActivity.java
@@ -0,0 +1,69 @@
+/*
+ * 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+
+/**
+ * Draws hundreds of levels of overdraw over the content area.
+ *
+ * This should all be optimized out by the renderer.
+ */
+public class FullscreenOverdrawActivity extends AppCompatActivity {
+    private class OverdrawView extends View {
+        Paint paint = new Paint();
+        int mColorValue = 0;
+
+        public OverdrawView(Context context) {
+            super(context);
+        }
+
+        @SuppressWarnings("unused")
+        public void setColorValue(int colorValue) {
+            mColorValue = colorValue;
+            invalidate();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            paint.setColor(Color.rgb(mColorValue, 255 - mColorValue, 255));
+
+            for (int i = 0; i < 400; i++) {
+                canvas.drawRect(0, 0, getWidth(), getHeight(), paint);
+            }
+        }
+    }
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        OverdrawView overdrawView = new OverdrawView(this);
+        setContentView(overdrawView);
+
+        ObjectAnimator objectAnimator = ObjectAnimator.ofInt(overdrawView, "colorValue", 0, 255);
+        objectAnimator.setRepeatMode(ValueAnimator.REVERSE);
+        objectAnimator.setRepeatCount(ValueAnimator.INFINITE);
+        objectAnimator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
new file mode 100644
index 0000000..a12742d
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
@@ -0,0 +1,86 @@
+/*
+ * 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.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.graphics.SurfaceTexture;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.test.uibench.opengl.ImageFlipRenderThread;
+
+public class GlTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
+    private ImageFlipRenderThread mRenderThread;
+    private TextureView mTextureView;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mTextureView = new TextureView(this);
+        mTextureView.setSurfaceTextureListener(this);
+        setContentView(mTextureView, new FrameLayout.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT,
+                Gravity.CENTER));
+    }
+
+    @Override
+    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
+        mRenderThread = new ImageFlipRenderThread(getResources(), surface);
+        mRenderThread.start();
+
+        mTextureView.setCameraDistance(5000);
+
+        ObjectAnimator animator = ObjectAnimator.ofFloat(mTextureView, "rotationY", 0.0f, 360.0f);
+        animator.setRepeatMode(ObjectAnimator.REVERSE);
+        animator.setRepeatCount(ObjectAnimator.INFINITE);
+        animator.setDuration(4000);
+        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+            @Override
+            public void onAnimationUpdate(ValueAnimator animation) {
+                mTextureView.invalidate();
+            }
+        });
+        animator.start();
+    }
+
+    @Override
+    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+    }
+
+    @Override
+    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+        mRenderThread.finish();
+        try {
+            mRenderThread.join();
+        } catch (InterruptedException e) {
+            Log.e(ImageFlipRenderThread.LOG_TAG, "Could not wait for render thread");
+        }
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+    }
+
+}
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
new file mode 100644
index 0000000..84383ec
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/InflatingListActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class InflatingListActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<String>(this,
+                android.R.layout.simple_list_item_1, TextUtils.buildSimpleStringList()) {
+            @Override
+            public View getView(int position, View convertView, ViewGroup parent) {
+                // pathological getView behavior: drop convertView on the floor to force inflation
+                return super.getView(position, null, parent);
+            }
+        };
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java b/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java
new file mode 100644
index 0000000..93d67a6
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/InvalidateActivity.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.support.annotation.ColorInt;
+import android.support.v7.app.AppCompatActivity;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Tests invalidation performance by invalidating a large number of easily rendered views,
+ */
+public class InvalidateActivity extends AppCompatActivity {
+    public static class ColorView extends View {
+        @ColorInt
+        public int mColor;
+
+        public ColorView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+        }
+
+        public void setColor(@ColorInt int color) {
+            mColor = color;
+            invalidate();
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.drawColor(mColor);
+        }
+    }
+
+    ColorView[][] mColorViews;
+
+    @SuppressWarnings("unused")
+    public void setColorValue(int colorValue) {
+        @ColorInt int a = Color.rgb(colorValue, 255 - colorValue, 255);
+        @ColorInt int b = Color.rgb(255, colorValue, 255 - colorValue);
+        for (int y = 0; y < mColorViews.length; y++) {
+            for (int x = 0; x < mColorViews[y].length; x++) {
+                mColorViews[y][x].setColor((x + y) % 2 == 0 ? a : b);
+            }
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_invalidate);
+
+        ViewGroup root = (ViewGroup) findViewById(R.id.invalidate_root);
+        for (int y = 0; y < root.getChildCount(); y++) {
+            ViewGroup row = (ViewGroup) root.getChildAt(y);
+            if (mColorViews == null) {
+                mColorViews = new ColorView[root.getChildCount()][row.getChildCount()];
+            }
+
+            for (int x = 0; x < row.getChildCount(); x++) {
+                mColorViews[y][x] = (ColorView) row.getChildAt(x);
+            }
+        }
+
+        ObjectAnimator animator = ObjectAnimator.ofInt(this, "colorValue", 0, 255);
+        animator.setRepeatMode(ValueAnimator.REVERSE);
+        animator.setRepeatCount(ValueAnimator.INFINITE);
+        animator.start();
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/MainActivity.java b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
index 7c3391d..2111274 100644
--- a/tests/UiBench/src/com/android/test/uibench/MainActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
@@ -56,7 +56,7 @@
         if (fm.findFragmentById(android.R.id.content) == null) {
             ListFragment listFragment = new ListFragment() {
                 @Override
-                @SuppressWarnings({ "unchecked" })
+                @SuppressWarnings("unchecked")
                 public void onListItemClick(ListView l, View v, int position, long id) {
                     Map<String, Object> map = (Map<String, Object>)l.getItemAtPosition(position);
 
diff --git a/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
new file mode 100644
index 0000000..d32f071
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/ShadowGridActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.os.Bundle;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.ListFragment;
+import android.support.v7.app.AppCompatActivity;
+import android.view.View;
+import android.widget.ArrayAdapter;
+
+public class ShadowGridActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment() {
+                @Override
+                public void onViewCreated(View view, Bundle savedInstanceState) {
+                    super.onViewCreated(view, savedInstanceState);
+                    getListView().setDivider(null);
+                }
+            };
+
+            listFragment.setListAdapter(new ArrayAdapter<>(this,
+                    R.layout.card_row, R.id.card_text, TextUtils.buildSimpleStringList()));
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
new file mode 100644
index 0000000..91d74ac
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheHighHitrateActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.test.uibench;
+
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class TextCacheHighHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(80));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
new file mode 100644
index 0000000..b526cde
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextCacheLowHitrateActivity.java
@@ -0,0 +1,27 @@
+/*
+ * 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.test.uibench;
+
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+
+public class TextCacheLowHitrateActivity extends CompatListActivity {
+    @Override
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildParagraphListWithHitPercentage(20));
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TextUtils.java b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
new file mode 100644
index 0000000..d88ca1e
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TextUtils.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import java.util.Random;
+
+public class TextUtils {
+    private static final int STRING_COUNT = 200;
+    private static final int SIMPLE_STRING_LENGTH = 10;
+
+    /**
+     * Create word of random assortment of lower/upper case letters
+     */
+    private static String randomWord(Random random, int length) {
+        String result = "";
+        for (int j = 0; j < length; j++) {
+            // add random letter
+            int base = random.nextInt(2) == 0 ? 'A' : 'a';
+            result += (char)(random.nextInt(26) + base);
+        }
+        return result;
+    }
+
+    public static String[] buildSimpleStringList() {
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            strings[i] = randomWord(random, SIMPLE_STRING_LENGTH);
+        }
+        return strings;
+    }
+
+    // a small number of strings reused frequently, expected to hit
+    // in the word-granularity text layout cache
+    static final String[] CACHE_HIT_STRINGS = new String[] {
+            "a",
+            "small",
+            "number",
+            "of",
+            "strings",
+            "reused",
+            "frequently"
+    };
+
+    private static final int WORDS_IN_PARAGRAPH = 150;
+
+    // misses are fairly long 'words' to ensure they miss
+    private static final int PARAGRAPH_MISS_MIN_LENGTH = 4;
+    private static final int PARAGRAPH_MISS_MAX_LENGTH = 9;
+
+    static String[] buildParagraphListWithHitPercentage(int hitPercentage) {
+        if (hitPercentage < 0 || hitPercentage > 100) throw new IllegalArgumentException();
+
+        String[] strings = new String[STRING_COUNT];
+        Random random = new Random(0);
+        for (int i = 0; i < strings.length; i++) {
+            String result = "";
+            for (int word = 0; word < WORDS_IN_PARAGRAPH; word++) {
+                if (word != 0) {
+                    result += " ";
+                }
+                if (random.nextInt(100) < hitPercentage) {
+                    // add a common word, which is very likely to hit in the cache
+                    result += CACHE_HIT_STRINGS[random.nextInt(CACHE_HIT_STRINGS.length)];
+                } else {
+                    // construct a random word, which will *most likely* miss
+                    int length = PARAGRAPH_MISS_MIN_LENGTH;
+                    length += random.nextInt(PARAGRAPH_MISS_MAX_LENGTH - PARAGRAPH_MISS_MIN_LENGTH);
+
+                    result += randomWord(random, length);
+                }
+            }
+            strings[i] = result;
+        }
+
+        return strings;
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java
new file mode 100644
index 0000000..6e98472
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivity.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+
+public class TrivialAnimationActivity extends AppCompatActivity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().setBackgroundDrawable(new ColorDrawable() {
+            int colorValue = 0;
+            int colorDelta = 1;
+
+            @Override
+            public void draw(Canvas canvas) {
+                colorValue += colorDelta;
+                if (colorValue == 255 || colorValue == 0) {
+                    colorDelta *= -1;
+                }
+
+                setColor(Color.rgb(255, colorValue, 255 - colorValue));
+                invalidateSelf();
+                super.draw(canvas);
+            }
+        });
+    }
+}
diff --git a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
index 0af3471..339ac80 100644
--- a/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -15,41 +15,13 @@
  */
 package com.android.test.uibench;
 
-import android.os.Bundle;
-import android.support.v4.app.FragmentManager;
-import android.support.v4.app.ListFragment;
-import android.support.v7.app.AppCompatActivity;
 import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
 
-import java.util.Random;
-
-public class TrivialListActivity extends AppCompatActivity {
-    static final int STRING_LENGTH = 10;
-
-    static String[] buildStringList() {
-        String[] strings = new String[200];
-        Random random = new Random(0);
-        for (int i = 0; i < strings.length; i++) {
-            String result = "";
-            for (int j = 0; j < STRING_LENGTH; j++) {
-                // add random letter
-                result += (char)(random.nextInt(26) + 65);
-            }
-            strings[i] = result;
-        }
-        return strings;
-    }
-
+public class TrivialListActivity extends CompatListActivity {
     @Override
-    protected void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-
-        FragmentManager fm = getSupportFragmentManager();
-        if (fm.findFragmentById(android.R.id.content) == null) {
-            ListFragment listFragment = new ListFragment();
-            listFragment.setListAdapter(new ArrayAdapter<>(TrivialListActivity.this,
-                    android.R.layout.simple_list_item_1, buildStringList()));
-            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
-        }
+    protected ListAdapter createListAdapter() {
+        return new ArrayAdapter<>(this, android.R.layout.simple_list_item_1,
+                TextUtils.buildSimpleStringList());
     }
 }
diff --git a/tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java b/tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java
new file mode 100644
index 0000000..119ce52
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/opengl/ImageFlipRenderThread.java
@@ -0,0 +1,389 @@
+/*
+ * 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.test.uibench.opengl;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
+import android.util.Log;
+
+import com.android.test.uibench.R;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+import static android.opengl.GLES20.GL_CLAMP_TO_EDGE;
+import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
+import static android.opengl.GLES20.GL_COMPILE_STATUS;
+import static android.opengl.GLES20.GL_FLOAT;
+import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
+import static android.opengl.GLES20.GL_LINEAR;
+import static android.opengl.GLES20.GL_LINK_STATUS;
+import static android.opengl.GLES20.GL_NO_ERROR;
+import static android.opengl.GLES20.GL_RGBA;
+import static android.opengl.GLES20.GL_TEXTURE0;
+import static android.opengl.GLES20.GL_TEXTURE_2D;
+import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
+import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
+import static android.opengl.GLES20.GL_TEXTURE_WRAP_S;
+import static android.opengl.GLES20.GL_TEXTURE_WRAP_T;
+import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
+import static android.opengl.GLES20.GL_TRUE;
+import static android.opengl.GLES20.GL_UNSIGNED_BYTE;
+import static android.opengl.GLES20.GL_VERTEX_SHADER;
+import static android.opengl.GLES20.glActiveTexture;
+import static android.opengl.GLES20.glAttachShader;
+import static android.opengl.GLES20.glBindTexture;
+import static android.opengl.GLES20.glClear;
+import static android.opengl.GLES20.glClearColor;
+import static android.opengl.GLES20.glCompileShader;
+import static android.opengl.GLES20.glCreateProgram;
+import static android.opengl.GLES20.glCreateShader;
+import static android.opengl.GLES20.glDeleteProgram;
+import static android.opengl.GLES20.glDeleteShader;
+import static android.opengl.GLES20.glDrawArrays;
+import static android.opengl.GLES20.glEnableVertexAttribArray;
+import static android.opengl.GLES20.glGenTextures;
+import static android.opengl.GLES20.glGetAttribLocation;
+import static android.opengl.GLES20.glGetError;
+import static android.opengl.GLES20.glGetProgramInfoLog;
+import static android.opengl.GLES20.glGetProgramiv;
+import static android.opengl.GLES20.glGetShaderInfoLog;
+import static android.opengl.GLES20.glGetShaderiv;
+import static android.opengl.GLES20.glGetUniformLocation;
+import static android.opengl.GLES20.glLinkProgram;
+import static android.opengl.GLES20.glShaderSource;
+import static android.opengl.GLES20.glTexParameteri;
+import static android.opengl.GLES20.glUniform1i;
+import static android.opengl.GLES20.glUseProgram;
+import static android.opengl.GLES20.glVertexAttribPointer;
+
+public class ImageFlipRenderThread extends Thread {
+    public static final String LOG_TAG = "GLTextureView";
+
+    static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+    static final int EGL_OPENGL_ES2_BIT = 4;
+
+    private volatile boolean mFinished;
+
+    private final Resources mResources;
+    private final SurfaceTexture mSurface;
+
+    private EGL10 mEgl;
+    private EGLDisplay mEglDisplay;
+    private EGLConfig mEglConfig;
+    private EGLContext mEglContext;
+    private EGLSurface mEglSurface;
+
+    public ImageFlipRenderThread(Resources resources, SurfaceTexture surface) {
+        mResources = resources;
+        mSurface = surface;
+    }
+
+    private static final String sSimpleVS =
+            "attribute vec4 position;\n" +
+                    "attribute vec2 texCoords;\n" +
+                    "varying vec2 outTexCoords;\n" +
+                    "\nvoid main(void) {\n" +
+                    "    outTexCoords = texCoords;\n" +
+                    "    gl_Position = position;\n" +
+                    "}\n\n";
+    private static final String sSimpleFS =
+            "precision mediump float;\n\n" +
+                    "varying vec2 outTexCoords;\n" +
+                    "uniform sampler2D texture;\n" +
+                    "\nvoid main(void) {\n" +
+                    "    gl_FragColor = texture2D(texture, outTexCoords);\n" +
+                    "}\n\n";
+
+    private static final int FLOAT_SIZE_BYTES = 4;
+    private static final int TRIANGLE_VERTICES_DATA_STRIDE_BYTES = 5 * FLOAT_SIZE_BYTES;
+    private static final int TRIANGLE_VERTICES_DATA_POS_OFFSET = 0;
+    private static final int TRIANGLE_VERTICES_DATA_UV_OFFSET = 3;
+    private final float[] mTriangleVerticesData = {
+            // X, Y, Z, U, V
+            -1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
+            1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
+            -1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
+            1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
+    };
+
+    @Override
+    public void run() {
+        initGL();
+
+        FloatBuffer triangleVertices = ByteBuffer.allocateDirect(mTriangleVerticesData.length
+                * FLOAT_SIZE_BYTES).order(ByteOrder.nativeOrder()).asFloatBuffer();
+        triangleVertices.put(mTriangleVerticesData).position(0);
+
+        int texture = loadTexture(R.drawable.large_photo);
+        int program = buildProgram(sSimpleVS, sSimpleFS);
+
+        int attribPosition = glGetAttribLocation(program, "position");
+        checkGlError();
+
+        int attribTexCoords = glGetAttribLocation(program, "texCoords");
+        checkGlError();
+
+        int uniformTexture = glGetUniformLocation(program, "texture");
+        checkGlError();
+
+        glBindTexture(GL_TEXTURE_2D, texture);
+        checkGlError();
+
+        glUseProgram(program);
+        checkGlError();
+
+        glEnableVertexAttribArray(attribPosition);
+        checkGlError();
+
+        glEnableVertexAttribArray(attribTexCoords);
+        checkGlError();
+
+        glUniform1i(uniformTexture, 0);
+        checkGlError();
+
+        // drawQuad
+        triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
+        glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+        checkGlError();
+
+        triangleVertices.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
+        glVertexAttribPointer(attribTexCoords, 3, GL_FLOAT, false,
+                TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
+        checkGlError();
+
+        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+        checkGlError();
+
+        while (!mFinished) {
+            checkCurrent();
+
+            glClear(GL_COLOR_BUFFER_BIT);
+            checkGlError();
+
+            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+            checkGlError();
+
+            if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
+                throw new RuntimeException("Cannot swap buffers");
+            }
+            checkEglError();
+
+            try {
+                Thread.sleep(2000);
+            } catch (InterruptedException e) {
+                // Ignore
+            }
+        }
+
+        finishGL();
+    }
+
+    private int loadTexture(int resource) {
+        int[] textures = new int[1];
+
+        glActiveTexture(GL_TEXTURE0);
+        glGenTextures(1, textures, 0);
+        checkGlError();
+
+        int texture = textures[0];
+        glBindTexture(GL_TEXTURE_2D, texture);
+        checkGlError();
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+        Bitmap bitmap = BitmapFactory.decodeResource(mResources, resource);
+
+        GLUtils.texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bitmap, GL_UNSIGNED_BYTE, 0);
+        checkGlError();
+
+        bitmap.recycle();
+
+        return texture;
+    }
+
+    private static int buildProgram(String vertex, String fragment) {
+        int vertexShader = buildShader(vertex, GL_VERTEX_SHADER);
+        if (vertexShader == 0) return 0;
+
+        int fragmentShader = buildShader(fragment, GL_FRAGMENT_SHADER);
+        if (fragmentShader == 0) return 0;
+
+        int program = glCreateProgram();
+        glAttachShader(program, vertexShader);
+        checkGlError();
+
+        glAttachShader(program, fragmentShader);
+        checkGlError();
+
+        glLinkProgram(program);
+        checkGlError();
+
+        int[] status = new int[1];
+        glGetProgramiv(program, GL_LINK_STATUS, status, 0);
+        if (status[0] != GL_TRUE) {
+            String error = glGetProgramInfoLog(program);
+            Log.d(LOG_TAG, "Error while linking program:\n" + error);
+            glDeleteShader(vertexShader);
+            glDeleteShader(fragmentShader);
+            glDeleteProgram(program);
+            return 0;
+        }
+
+        return program;
+    }
+
+    private static int buildShader(String source, int type) {
+        int shader = glCreateShader(type);
+
+        glShaderSource(shader, source);
+        checkGlError();
+
+        glCompileShader(shader);
+        checkGlError();
+
+        int[] status = new int[1];
+        glGetShaderiv(shader, GL_COMPILE_STATUS, status, 0);
+        if (status[0] != GL_TRUE) {
+            String error = glGetShaderInfoLog(shader);
+            Log.d(LOG_TAG, "Error while compiling shader:\n" + error);
+            glDeleteShader(shader);
+            return 0;
+        }
+
+        return shader;
+    }
+
+    private void checkEglError() {
+        int error = mEgl.eglGetError();
+        if (error != EGL10.EGL_SUCCESS) {
+            Log.w(LOG_TAG, "EGL error = 0x" + Integer.toHexString(error));
+        }
+    }
+
+    private static void checkGlError() {
+        int error = glGetError();
+        if (error != GL_NO_ERROR) {
+            Log.w(LOG_TAG, "GL error = 0x" + Integer.toHexString(error));
+        }
+    }
+
+    private void finishGL() {
+        mEgl.eglDestroyContext(mEglDisplay, mEglContext);
+        mEgl.eglDestroySurface(mEglDisplay, mEglSurface);
+    }
+
+    private void checkCurrent() {
+        if (!mEglContext.equals(mEgl.eglGetCurrentContext()) ||
+                !mEglSurface.equals(mEgl.eglGetCurrentSurface(EGL10.EGL_DRAW))) {
+            if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+                throw new RuntimeException("eglMakeCurrent failed "
+                        + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+            }
+        }
+    }
+
+    private void initGL() {
+        mEgl = (EGL10) EGLContext.getEGL();
+
+        mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+        if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
+            throw new RuntimeException("eglGetDisplay failed "
+                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+
+        int[] version = new int[2];
+        if (!mEgl.eglInitialize(mEglDisplay, version)) {
+            throw new RuntimeException("eglInitialize failed " +
+                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+
+        mEglConfig = chooseEglConfig();
+        if (mEglConfig == null) {
+            throw new RuntimeException("eglConfig not initialized");
+        }
+
+        mEglContext = createContext(mEgl, mEglDisplay, mEglConfig);
+
+        mEglSurface = mEgl.eglCreateWindowSurface(mEglDisplay, mEglConfig, mSurface, null);
+
+        if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE) {
+            int error = mEgl.eglGetError();
+            if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+                Log.e(LOG_TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+                return;
+            }
+            throw new RuntimeException("createWindowSurface failed "
+                    + GLUtils.getEGLErrorString(error));
+        }
+
+        if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext)) {
+            throw new RuntimeException("eglMakeCurrent failed "
+                    + GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        }
+    }
+
+
+    EGLContext createContext(EGL10 egl, EGLDisplay eglDisplay, EGLConfig eglConfig) {
+        int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
+        return egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+    }
+
+    private EGLConfig chooseEglConfig() {
+        int[] configsCount = new int[1];
+        EGLConfig[] configs = new EGLConfig[1];
+        int[] configSpec = getConfig();
+        if (!mEgl.eglChooseConfig(mEglDisplay, configSpec, configs, 1, configsCount)) {
+            throw new IllegalArgumentException("eglChooseConfig failed " +
+                    GLUtils.getEGLErrorString(mEgl.eglGetError()));
+        } else if (configsCount[0] > 0) {
+            return configs[0];
+        }
+        return null;
+    }
+
+    private static int[] getConfig() {
+        return new int[]{
+                EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+                EGL10.EGL_RED_SIZE, 8,
+                EGL10.EGL_GREEN_SIZE, 8,
+                EGL10.EGL_BLUE_SIZE, 8,
+                EGL10.EGL_ALPHA_SIZE, 8,
+                EGL10.EGL_DEPTH_SIZE, 0,
+                EGL10.EGL_STENCIL_SIZE, 0,
+                EGL10.EGL_NONE
+        };
+    }
+
+    public void finish() {
+        mFinished = true;
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 6177784..95f676e 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -32,7 +32,7 @@
  */
 public class WindowManagerPermissionTests extends TestCase {
     IWindowManager mWm;
-    
+
     @Override
     protected void setUp() throws Exception {
         super.setUp();
@@ -51,7 +51,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.resumeKeyDispatching(null);
             fail("IWindowManager.resumeKeyDispatching did not throw SecurityException as"
@@ -61,7 +61,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setEventDispatching(true);
             fail("IWindowManager.setEventDispatching did not throw SecurityException as"
@@ -71,7 +71,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.addWindowToken(null, 0);
             fail("IWindowManager.addWindowToken did not throw SecurityException as"
@@ -81,7 +81,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeWindowToken(null);
             fail("IWindowManager.removeWindowToken did not throw SecurityException as"
@@ -91,9 +91,10 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null);
+            mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
+                    Configuration.EMPTY);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -101,9 +102,9 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
-            mWm.setAppTask(null, 0, null);
+            mWm.setAppTask(null, 0, null, null);
             fail("IWindowManager.setAppGroupId did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
@@ -111,7 +112,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.updateOrientationFromAppTokens(new Configuration(), null);
             fail("IWindowManager.updateOrientationFromAppTokens did not throw SecurityException as"
@@ -121,7 +122,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppOrientation(null, 0);
             mWm.addWindowToken(null, 0);
@@ -132,7 +133,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setFocusedApp(null, false);
             fail("IWindowManager.setFocusedApp did not throw SecurityException as"
@@ -142,7 +143,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.prepareAppTransition(0, false);
             fail("IWindowManager.prepareAppTransition did not throw SecurityException as"
@@ -152,7 +153,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.executeAppTransition();
             fail("IWindowManager.executeAppTransition did not throw SecurityException as"
@@ -162,7 +163,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppStartingWindow(null, "foo", 0, null, null, 0, 0, 0, 0, null, false);
             fail("IWindowManager.setAppStartingWindow did not throw SecurityException as"
@@ -172,7 +173,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppWillBeHidden(null);
             fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
@@ -182,7 +183,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAppVisibility(null, false);
             fail("IWindowManager.setAppVisibility did not throw SecurityException as"
@@ -192,7 +193,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.startAppFreezingScreen(null, 0);
             fail("IWindowManager.startAppFreezingScreen did not throw SecurityException as"
@@ -202,7 +203,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.stopAppFreezingScreen(null, false);
             fail("IWindowManager.stopAppFreezingScreen did not throw SecurityException as"
@@ -212,7 +213,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.removeAppToken(null);
             fail("IWindowManager.removeAppToken did not throw SecurityException as"
@@ -236,7 +237,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.reenableKeyguard(token);
             fail("IWindowManager.reenableKeyguard did not throw SecurityException as"
@@ -246,7 +247,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.exitKeyguardSecurely(null);
             fail("IWindowManager.exitKeyguardSecurely did not throw SecurityException as"
@@ -257,7 +258,7 @@
             fail("Unexpected remote exception");
         }
     }
-        
+
     @SmallTest
     public void testSET_ANIMATION_SCALE() {
         try {
@@ -269,7 +270,7 @@
         } catch (RemoteException e) {
             fail("Unexpected remote exception");
         }
-        
+
         try {
             mWm.setAnimationScales(new float[1]);
             fail("IWindowManager.setAnimationScales did not throw SecurityException as"
@@ -280,7 +281,7 @@
             fail("Unexpected remote exception");
         }
     }
-    
+
     @SmallTest
     public void testSET_ORIENTATION() {
         try {
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index 769e2a1..b701445 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -54,7 +54,6 @@
     tests/ResourceFilter_test.cpp \
     tests/ResourceTable_test.cpp
 
-aaptHostLdLibs :=
 aaptHostStaticLibs := \
     libandroidfw \
     libpng \
@@ -68,17 +67,13 @@
 aaptCFlags := -DAAPT_VERSION=\"$(BUILD_NUMBER_FROM_FILE)\"
 aaptCFlags += -Wall -Werror
 
-ifeq ($(HOST_OS),linux)
-    aaptHostLdLibs += -lrt -ldl -lpthread
-endif
+aaptHostLdLibs_linux := -lrt -ldl -lpthread
 
 # Statically link libz for MinGW (Win SDK under Linux),
 # and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
-    aaptHostStaticLibs += libz
-else
-    aaptHostLdLibs += -lz
-endif
+aaptHostStaticLibs_windows := libz
+aaptHostLdLibs_linux += -lz
+aaptHostLdLibs_darwin := -lz
 
 
 # ==========================================================
@@ -87,13 +82,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := libaapt
-LOCAL_CFLAGS += -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-ifeq (darwin,$(HOST_OS))
-LOCAL_CFLAGS += -D_DARWIN_UNLIMITED_STREAMS
-endif
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wno-format-y2k -DSTATIC_ANDROIDFW_FOR_TOOLS $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_CFLAGS_darwin := -D_DARWIN_UNLIMITED_STREAMS
 LOCAL_SRC_FILES := $(aaptSources)
-LOCAL_STATIC_LIBRARIES += $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -103,11 +98,14 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := aapt
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
 LOCAL_SRC_FILES := $(aaptMain)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_EXECUTABLE)
 
@@ -116,15 +114,16 @@
 # Build the host tests: libaapt_tests
 # ==========================================================
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_MODULE := libaapt_tests
-LOCAL_CFLAGS += $(aaptCFlags)
-LOCAL_CPPFLAGS += $(aaptCppFlags)
-LOCAL_LDLIBS += $(aaptHostLdLibs)
-LOCAL_SRC_FILES += $(aaptTests)
-LOCAL_C_INCLUDES += $(LOCAL_PATH)
-LOCAL_STATIC_LIBRARIES += libaapt $(aaptHostStaticLibs)
+LOCAL_CFLAGS := $(aaptCFlags)
+LOCAL_CPPFLAGS := $(aaptCppFlags)
+LOCAL_LDLIBS_darwin := $(aaptHostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(aaptHostLdLibs_linux)
+LOCAL_SRC_FILES := $(aaptTests)
+LOCAL_C_INCLUDES := $(LOCAL_PATH)
+LOCAL_STATIC_LIBRARIES := libaapt $(aaptHostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(aaptHostStaticLibs_windows)
 
 include $(BUILD_HOST_NATIVE_TEST)
 
diff --git a/tools/aidl/AST.h b/tools/aidl/AST.h
index ead5e7a..d7bfccb 100644
--- a/tools/aidl/AST.h
+++ b/tools/aidl/AST.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_AST_H
-#define AIDL_AST_H
+#ifndef AIDL_AST_H_
+#define AIDL_AST_H_
 
 #include <string>
 #include <vector>
@@ -368,4 +368,4 @@
     virtual void Write(FILE* to);
 };
 
-#endif // AIDL_AST_H
+#endif // AIDL_AST_H_
diff --git a/tools/aidl/Android.mk b/tools/aidl/Android.mk
index efd60a2..8e6189f 100644
--- a/tools/aidl/Android.mk
+++ b/tools/aidl/Android.mk
@@ -6,24 +6,74 @@
 ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
 
 LOCAL_PATH:= $(call my-dir)
+
+# Logic shared between aidl and its unittests
 include $(CLEAR_VARS)
+LOCAL_MODULE := libaidl-common
+
+LOCAL_CLANG_CFLAGS := -Wall -Werror
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS += -Wno-unused-parameter
+# yacc dumps a lot of code *just in case*.
+LOCAL_CLANG_CFLAGS += -Wno-unused-function
+LOCAL_CLANG_CFLAGS += -Wno-unneeded-internal-declaration
+# yacc is a tool from a more civilized age.
+LOCAL_CLANG_CFLAGS += -Wno-deprecated-register
+# yacc also has a habit of using char* over const char*.
+LOCAL_CLANG_CFLAGS += -Wno-writable-strings
 
 LOCAL_SRC_FILES := \
-	aidl_language_l.l \
-	aidl_language_y.y \
-	aidl.cpp \
-	aidl_language.cpp \
-	options.cpp \
-	search_path.cpp \
-	AST.cpp \
-	Type.cpp \
-	generate_java.cpp \
-	generate_java_binder.cpp \
-	generate_java_rpc.cpp
+    AST.cpp \
+    Type.cpp \
+    aidl.cpp \
+    aidl_language.cpp \
+    aidl_language_l.l \
+    aidl_language_y.y \
+    generate_java.cpp \
+    generate_java_binder.cpp \
+    options.cpp \
+    search_path.cpp \
 
-LOCAL_CFLAGS := -g
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# aidl executable
+include $(CLEAR_VARS)
 LOCAL_MODULE := aidl
 
+LOCAL_MODULE_HOST_OS := darwin linux windows
+LOCAL_CFLAGS := -Wall -Werror
+LOCAL_SRC_FILES := main.cpp
+LOCAL_STATIC_LIBRARIES := libaidl-common
 include $(BUILD_HOST_EXECUTABLE)
 
+
+# TODO(wiley) Compile these for mac as well after b/22771504
+ifeq ($(HOST_OS),linux)
+# Unit tests
+include $(CLEAR_VARS)
+LOCAL_MODULE := aidl_unittests
+
+LOCAL_CFLAGS := -g -DUNIT_TEST -Wall -Werror
+# Tragically, the code is riddled with unused parameters.
+LOCAL_CLANG_CFLAGS := -Wno-unused-parameter
+LOCAL_SRC_FILES := \
+    options_unittest.cpp \
+    test_main.cpp \
+    tests/end_to_end_tests.cpp \
+    tests/example_interface_test_data.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+    libchrome-host \
+
+LOCAL_STATIC_LIBRARIES := \
+    libaidl-common \
+    libgmock_host \
+    libgtest_host \
+
+LOCAL_LDLIBS_linux := -lrt
+
+include $(BUILD_HOST_NATIVE_TEST)
+endif # HOST_OS == linux
+
 endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 2267750..d9b8b88 100644
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -28,9 +28,6 @@
 Type* MAP_TYPE;
 Type* LIST_TYPE;
 Type* CLASSLOADER_TYPE;
-Type* RPC_DATA_TYPE;
-Type* RPC_ERROR_TYPE;
-Type* EVENT_FAKE_TYPE;
 
 Expression* NULL_VALUE;
 Expression* THIS_VALUE;
@@ -42,7 +39,6 @@
 register_base_types()
 {
     VOID_TYPE = new BasicType("void",
-            "XXX", "XXX", "XXX", "XXX", "XXX",
             "XXX", "XXX", "XXX", "XXX", "XXX");
     NAMES.Add(VOID_TYPE);
 
@@ -50,37 +46,37 @@
     NAMES.Add(BOOLEAN_TYPE);
 
     BYTE_TYPE = new BasicType("byte",
-            "writeByte", "readByte", "writeByteArray", "createByteArray", "readByteArray",
-            "putByte", "getByte", "putByteArray", "createByteArray", "getByteArray");
+            "writeByte", "readByte", "writeByteArray", "createByteArray",
+            "readByteArray");
     NAMES.Add(BYTE_TYPE);
 
     CHAR_TYPE = new CharType();
     NAMES.Add(CHAR_TYPE);
 
     INT_TYPE = new BasicType("int",
-            "writeInt", "readInt", "writeIntArray", "createIntArray", "readIntArray",
-            "putInteger", "getInteger", "putIntegerArray", "createIntegerArray", "getIntegerArray");
+            "writeInt", "readInt", "writeIntArray", "createIntArray",
+            "readIntArray");
     NAMES.Add(INT_TYPE);
 
     LONG_TYPE = new BasicType("long",
-            "writeLong", "readLong", "writeLongArray", "createLongArray", "readLongArray",
-            "putLong", "getLong", "putLongArray", "createLongArray", "getLongArray");
+            "writeLong", "readLong", "writeLongArray", "createLongArray",
+            "readLongArray");
     NAMES.Add(LONG_TYPE);
 
     FLOAT_TYPE = new BasicType("float",
-            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray", "readFloatArray",
-            "putFloat", "getFloat", "putFloatArray", "createFloatArray", "getFloatArray");
+            "writeFloat", "readFloat", "writeFloatArray", "createFloatArray",
+            "readFloatArray");
     NAMES.Add(FLOAT_TYPE);
 
     DOUBLE_TYPE = new BasicType("double",
-            "writeDouble", "readDouble", "writeDoubleArray", "createDoubleArray", "readDoubleArray",
-            "putDouble", "getDouble", "putDoubleArray", "createDoubleArray", "getDoubleArray");
+            "writeDouble", "readDouble", "writeDoubleArray",
+            "createDoubleArray", "readDoubleArray");
     NAMES.Add(DOUBLE_TYPE);
 
     STRING_TYPE = new StringType();
     NAMES.Add(STRING_TYPE);
 
-    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false, false);
+    OBJECT_TYPE = new Type("java.lang", "Object", Type::BUILT_IN, false, false);
     NAMES.Add(OBJECT_TYPE);
 
     CHAR_SEQUENCE_TYPE = new CharSequenceType();
@@ -92,7 +88,7 @@
     LIST_TYPE = new ListType();
     NAMES.Add(LIST_TYPE);
 
-    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false, false);
+    TEXT_UTILS_TYPE = new Type("android.text", "TextUtils", Type::BUILT_IN, false, false);
     NAMES.Add(TEXT_UTILS_TYPE);
 
     REMOTE_EXCEPTION_TYPE = new RemoteExceptionType();
@@ -119,19 +115,9 @@
     PARCELABLE_INTERFACE_TYPE = new ParcelableInterfaceType();
     NAMES.Add(PARCELABLE_INTERFACE_TYPE);
 
-    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false, false);
+    CONTEXT_TYPE = new Type("android.content", "Context", Type::BUILT_IN, false, false);
     NAMES.Add(CONTEXT_TYPE);
 
-    RPC_DATA_TYPE = new RpcDataType();
-    NAMES.Add(RPC_DATA_TYPE);
-
-    RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
-                                    true, __FILE__, __LINE__);
-    NAMES.Add(RPC_ERROR_TYPE);
-
-    EVENT_FAKE_TYPE = new Type("event", Type::BUILT_IN, false, false, false);
-    NAMES.Add(EVENT_FAKE_TYPE);
-
     CLASSLOADER_TYPE = new ClassLoaderType();
     NAMES.Add(CLASSLOADER_TYPE);
 
@@ -158,30 +144,27 @@
 
 // ================================================================
 
-Type::Type(const string& name, int kind, bool canWriteToParcel, bool canWriteToRpcData,
-        bool canBeOut)
+Type::Type(const string& name, int kind, bool canWriteToParcel, bool canBeOut)
     :m_package(),
      m_name(name),
      m_declFile(""),
      m_declLine(-1),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
-     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     m_qualifiedName = name;
 }
 
 Type::Type(const string& package, const string& name,
-            int kind, bool canWriteToParcel, bool canWriteToRpcData,
-            bool canBeOut, const string& declFile, int declLine)
+            int kind, bool canWriteToParcel, bool canBeOut,
+            const string& declFile, int declLine)
     :m_package(package),
      m_name(name),
      m_declFile(declFile),
      m_declLine(declLine),
      m_kind(kind),
      m_canWriteToParcel(canWriteToParcel),
-     m_canWriteToRpcData(canWriteToRpcData),
      m_canBeOut(canBeOut)
 {
     if (package.length() > 0) {
@@ -214,12 +197,6 @@
 }
 
 string
-Type::RpcCreatorName() const
-{
-    return "";
-}
-
-string
 Type::InstantiableName() const
 {
     return QualifiedName();
@@ -282,26 +259,6 @@
 }
 
 void
-Type::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* WriteToRpcData error "
-                + m_qualifiedName + " */"));
-}
-
-void
-Type::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    fprintf(stderr, "aidl:internal error %s:%d qualifiedName=%s\n",
-            __FILE__, __LINE__, m_qualifiedName.c_str());
-    addTo->Add(new LiteralExpression("/* ReadFromRpcData error "
-                + m_qualifiedName + " */"));
-}
-
-void
 Type::SetQualifiedName(const string& qualified)
 {
     m_qualifiedName = qualified;
@@ -324,20 +281,13 @@
 
 BasicType::BasicType(const string& name, const string& marshallParcel,
           const string& unmarshallParcel, const string& writeArrayParcel,
-          const string& createArrayParcel, const string& readArrayParcel,
-          const string& marshallRpc, const string& unmarshallRpc,
-          const string& writeArrayRpc, const string& createArrayRpc, const string& readArrayRpc)
-    :Type(name, BUILT_IN, true, true, false),
+          const string& createArrayParcel, const string& readArrayParcel)
+    :Type(name, BUILT_IN, true, false),
      m_marshallParcel(marshallParcel),
      m_unmarshallParcel(unmarshallParcel),
      m_writeArrayParcel(writeArrayParcel),
      m_createArrayParcel(createArrayParcel),
-     m_readArrayParcel(readArrayParcel),
-     m_marshallRpc(marshallRpc),
-     m_unmarshallRpc(unmarshallRpc),
-     m_writeArrayRpc(writeArrayRpc),
-     m_createArrayRpc(createArrayRpc),
-     m_readArrayRpc(readArrayRpc)
+     m_readArrayParcel(readArrayParcel)
 {
 }
 
@@ -378,24 +328,10 @@
     addTo->Add(new MethodCall(parcel, m_readArrayParcel, 1, v));
 }
 
-void
-BasicType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, m_marshallRpc, 2, k, v));
-}
-
-void
-BasicType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, m_unmarshallRpc, 1, k)));
-}
-
 // ================================================================
 
 BooleanType::BooleanType()
-    :Type("boolean", BUILT_IN, true, true, false)
+    :Type("boolean", BUILT_IN, true, false)
 {
 }
 
@@ -439,24 +375,10 @@
     addTo->Add(new MethodCall(parcel, "readBooleanArray", 1, v));
 }
 
-void
-BooleanType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putBoolean", 2, k, v));
-}
-
-void
-BooleanType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getBoolean", 1, k)));
-}
-
 // ================================================================
 
 CharType::CharType()
-    :Type("char", BUILT_IN, true, true, false)
+    :Type("char", BUILT_IN, true, false)
 {
 }
 
@@ -498,24 +420,10 @@
     addTo->Add(new MethodCall(parcel, "readCharArray", 1, v));
 }
 
-void
-CharType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putChar", 2, k, v));
-}
-
-void
-CharType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getChar", 1, k)));
-}
-
 // ================================================================
 
 StringType::StringType()
-    :Type("java.lang", "String", BUILT_IN, true, true, false)
+    :Type("java.lang", "String", BUILT_IN, true, false)
 {
 }
 
@@ -562,24 +470,10 @@
     addTo->Add(new MethodCall(parcel, "readStringArray", 1, v));
 }
 
-void
-StringType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putString", 2, k, v));
-}
-
-void
-StringType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, Variable**)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getString", 1, k)));
-}
-
 // ================================================================
 
 CharSequenceType::CharSequenceType()
-    :Type("java.lang", "CharSequence", BUILT_IN, true, true, false)
+    :Type("java.lang", "CharSequence", BUILT_IN, true, false)
 {
 }
 
@@ -639,7 +533,7 @@
 // ================================================================
 
 RemoteExceptionType::RemoteExceptionType()
-    :Type("android.os", "RemoteException", BUILT_IN, false, false, false)
+    :Type("android.os", "RemoteException", BUILT_IN, false, false)
 {
 }
 
@@ -658,7 +552,7 @@
 // ================================================================
 
 RuntimeExceptionType::RuntimeExceptionType()
-    :Type("java.lang", "RuntimeException", BUILT_IN, false, false, false)
+    :Type("java.lang", "RuntimeException", BUILT_IN, false, false)
 {
 }
 
@@ -678,7 +572,7 @@
 // ================================================================
 
 IBinderType::IBinderType()
-    :Type("android.os", "IBinder", BUILT_IN, true, false, false)
+    :Type("android.os", "IBinder", BUILT_IN, true, false)
 {
 }
 
@@ -717,7 +611,7 @@
 // ================================================================
 
 IInterfaceType::IInterfaceType()
-    :Type("android.os", "IInterface", BUILT_IN, false, false, false)
+    :Type("android.os", "IInterface", BUILT_IN, false, false)
 {
 }
 
@@ -737,7 +631,7 @@
 // ================================================================
 
 BinderType::BinderType()
-    :Type("android.os", "Binder", BUILT_IN, false, false, false)
+    :Type("android.os", "Binder", BUILT_IN, false, false)
 {
 }
 
@@ -758,7 +652,7 @@
 // ================================================================
 
 BinderProxyType::BinderProxyType()
-    :Type("android.os", "BinderProxy", BUILT_IN, false, false, false)
+    :Type("android.os", "BinderProxy", BUILT_IN, false, false)
 {
 }
 
@@ -779,7 +673,7 @@
 // ================================================================
 
 ParcelType::ParcelType()
-    :Type("android.os", "Parcel", BUILT_IN, false, false, false)
+    :Type("android.os", "Parcel", BUILT_IN, false, false)
 {
 }
 
@@ -798,7 +692,7 @@
 // ================================================================
 
 ParcelableInterfaceType::ParcelableInterfaceType()
-    :Type("android.os", "Parcelable", BUILT_IN, false, false, false)
+    :Type("android.os", "Parcelable", BUILT_IN, false, false)
 {
 }
 
@@ -817,7 +711,7 @@
 // ================================================================
 
 MapType::MapType()
-    :Type("java.util", "Map", BUILT_IN, true, false, true)
+    :Type("java.util", "Map", BUILT_IN, true, true)
 {
 }
 
@@ -857,7 +751,7 @@
 // ================================================================
 
 ListType::ListType()
-    :Type("java.util", "List", BUILT_IN, true, true, true)
+    :Type("java.util", "List", BUILT_IN, true, true)
 {
 }
 
@@ -888,26 +782,12 @@
     addTo->Add(new MethodCall(parcel, "readList", 2, v, *cl));
 }
 
-void
-ListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putList", 2, k, v));
-}
-
-void
-ListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getList", 1, k)));
-}
-
 // ================================================================
 
 UserDataType::UserDataType(const string& package, const string& name,
-                        bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                        bool builtIn, bool canWriteToParcel,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel, canWriteToRpcData,
+    :Type(package, name, builtIn ? BUILT_IN : USERDATA, canWriteToParcel,
             true, declFile, declLine)
 {
 }
@@ -918,12 +798,6 @@
     return QualifiedName() + ".CREATOR";
 }
 
-string
-UserDataType::RpcCreatorName() const
-{
-    return QualifiedName() + ".RPC_CREATOR";
-}
-
 void
 UserDataType::WriteToParcel(StatementBlock* addTo, Variable* v, Variable* parcel, int flags)
 {
@@ -1014,29 +888,12 @@
                     v, new LiteralExpression(creator)));
 }
 
-void
-UserDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags)
-{
-    // data.putFlattenable(k, v);
-    addTo->Add(new MethodCall(data, "putFlattenable", 2, k, v));
-}
-
-void
-UserDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl)
-{
-    // data.getFlattenable(k, CLASS.RPC_CREATOR);
-    addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenable", 2, k,
-                new FieldVariable(v->type, "RPC_CREATOR"))));
-}
-
 // ================================================================
 
 InterfaceType::InterfaceType(const string& package, const string& name,
                         bool builtIn, bool oneway,
                         const string& declFile, int declLine)
-    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false, false,
+    :Type(package, name, builtIn ? BUILT_IN : INTERFACE, true, false,
                         declFile, declLine)
     ,m_oneway(oneway)
 {
@@ -1075,7 +932,7 @@
 
 GenericType::GenericType(const string& package, const string& name,
                          const vector<Type*>& args)
-    :Type(package, name, BUILT_IN, true, true, true)
+    :Type(package, name, BUILT_IN, true, true)
 {
     m_args = args;
 
@@ -1200,65 +1057,11 @@
     }
 }
 
-void
-GenericListType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    Type* generic = GenericArgumentTypes()[0];
-    if (generic == RPC_DATA_TYPE) {
-        addTo->Add(new MethodCall(data, "putRpcDataList", 2, k, v));
-    } else if (generic->RpcCreatorName() != "") {
-        addTo->Add(new MethodCall(data, "putFlattenableList", 2, k, v));
-    } else {
-        addTo->Add(new MethodCall(data, "putList", 2, k, v));
-    }
-}
-
-void
-GenericListType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, Variable** cl)
-{
-    Type* generic = GenericArgumentTypes()[0];
-    if (generic == RPC_DATA_TYPE) {
-        addTo->Add(new Assignment(v, new MethodCall(data, "getRpcDataList", 2, k)));
-    } else if (generic->RpcCreatorName() != "") {
-        addTo->Add(new Assignment(v, new MethodCall(data, "getFlattenableList", 2, k, 
-                        new LiteralExpression(generic->RpcCreatorName()))));
-    } else {
-        string classArg = GenericArgumentTypes()[0]->QualifiedName();
-        classArg += ".class";
-        addTo->Add(new Assignment(v, new MethodCall(data, "getList", 2, k,
-                        new LiteralExpression(classArg))));
-    }
-}
-
-
-// ================================================================
-
-RpcDataType::RpcDataType()
-    :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
-{
-}
-
-void
-RpcDataType::WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data, int flags)
-{
-    addTo->Add(new MethodCall(data, "putRpcData", 2, k, v));
-}
-
-void
-RpcDataType::CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v, Variable* data,
-        Variable** cl)
-{
-    addTo->Add(new Assignment(v, new MethodCall(data, "getRpcData", 1, k)));
-}
-
 
 // ================================================================
 
 ClassLoaderType::ClassLoaderType()
-    :Type("java.lang", "ClassLoader", BUILT_IN, false, false, false)
+    :Type("java.lang", "ClassLoader", BUILT_IN, false, false)
 {
 }
 
diff --git a/tools/aidl/Type.h b/tools/aidl/Type.h
index ae12720..6ede79a 100644
--- a/tools/aidl/Type.h
+++ b/tools/aidl/Type.h
@@ -1,5 +1,5 @@
-#ifndef AIDL_TYPE_H
-#define AIDL_TYPE_H
+#ifndef AIDL_TYPE_H_
+#define AIDL_TYPE_H_
 
 #include "AST.h"
 #include <string>
@@ -24,9 +24,9 @@
     };
 
                     Type(const string& name, int kind, bool canWriteToParcel,
-                            bool canWriteToRpcData, bool canBeOut);
+                         bool canBeOut);
                     Type(const string& package, const string& name,
-                            int kind, bool canWriteToParcel, bool canWriteToRpcData, bool canBeOut,
+                            int kind, bool canWriteToParcel, bool canBeOut,
                             const string& declFile = "", int declLine = -1);
     virtual         ~Type();
 
@@ -37,12 +37,10 @@
     inline string   DeclFile() const            { return m_declFile; }
     inline int      DeclLine() const            { return m_declLine; }
     inline bool     CanWriteToParcel() const    { return m_canWriteToParcel; }
-    inline bool     CanWriteToRpcData() const   { return m_canWriteToRpcData; }
     inline bool     CanBeOutParameter() const   { return m_canBeOut; }
     
     virtual string  ImportType() const;
     virtual string  CreatorName() const;
-    virtual string  RpcCreatorName() const;
     virtual string  InstantiableName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
@@ -61,11 +59,6 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-
 protected:
     void SetQualifiedName(const string& qualified);
     Expression* BuildWriteToParcelFlags(int flags);
@@ -81,7 +74,6 @@
     int m_declLine;
     int m_kind;
     bool m_canWriteToParcel;
-    bool m_canWriteToRpcData;
     bool m_canBeOut;
 };
 
@@ -93,12 +85,7 @@
                               const string& unmarshallParcel,
                               const string& writeArrayParcel,
                               const string& createArrayParcel,
-                              const string& readArrayParcel,
-                              const string& marshallRpc,
-                              const string& unmarshallRpc,
-                              const string& writeArrayRpc,
-                              const string& createArrayRpc,
-                              const string& readArrayRpc);
+                              const string& readArrayParcel);
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -114,22 +101,12 @@
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-
 private:
     string m_marshallParcel;
     string m_unmarshallParcel;
     string m_writeArrayParcel;
     string m_createArrayParcel;
     string m_readArrayParcel;
-    string m_marshallRpc;
-    string m_unmarshallRpc;
-    string m_writeArrayRpc;
-    string m_createArrayRpc;
-    string m_readArrayRpc;
 };
 
 class BooleanType : public Type
@@ -150,11 +127,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class CharType : public Type
@@ -175,11 +147,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 
@@ -203,11 +170,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class CharSequenceType : public Type
@@ -344,22 +306,16 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class UserDataType : public Type
 {
 public:
                     UserDataType(const string& package, const string& name,
-                            bool builtIn, bool canWriteToParcel, bool canWriteToRpcData,
+                            bool builtIn, bool canWriteToParcel,
                             const string& declFile = "", int declLine = -1);
 
     virtual string  CreatorName() const;
-    virtual string  RpcCreatorName() const;
 
     virtual void    WriteToParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, int flags);
@@ -376,11 +332,6 @@
                                     Variable* parcel, Variable** cl);
     virtual void    ReadArrayFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
 };
 
 class InterfaceType : public Type
@@ -426,17 +377,6 @@
     vector<Type*> m_args;
 };
 
-class RpcDataType : public UserDataType
-{
-public:
-                    RpcDataType();
-
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-};
-
 class ClassLoaderType : public Type
 {
 public:
@@ -459,11 +399,6 @@
     virtual void    ReadFromParcel(StatementBlock* addTo, Variable* v,
                                     Variable* parcel, Variable** cl);
 
-    virtual void    WriteToRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, int flags);
-    virtual void    CreateFromRpcData(StatementBlock* addTo, Expression* k, Variable* v,
-                                    Variable* data, Variable** cl);
-    
 private:
     string m_creator;
 };
@@ -526,11 +461,6 @@
 
 extern Type* CONTEXT_TYPE;
 
-extern Type* RPC_DATA_TYPE;
-extern Type* RPC_ERROR_TYPE;
-extern Type* RPC_CONTEXT_TYPE;
-extern Type* EVENT_FAKE_TYPE;
-
 extern Expression* NULL_VALUE;
 extern Expression* THIS_VALUE;
 extern Expression* SUPER_VALUE;
@@ -539,4 +469,4 @@
 
 void register_base_types();
 
-#endif // AIDL_TYPE_H
+#endif // AIDL_TYPE_H_
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 438007f..832c51c 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -60,12 +60,9 @@
         }
         else if (d->item_type == USER_DATA_TYPE) {
             user_data_type* b = (user_data_type*)d;
-            if ((b->flattening_methods & PARCELABLE_DATA) != 0) {
+            if (b->parcelable) {
                 printf("parcelable %s %s;\n", b->package, b->name.data);
             }
-            if ((b->flattening_methods & RPC_DATA) != 0) {
-                printf("flattenable %s %s;\n", b->package, b->name.data);
-            }
         }
         else {
             printf("UNKNOWN d=0x%08lx d->item_type=%d\n", (long)d, d->item_type);
@@ -162,11 +159,6 @@
 {
 }
 
-static ParserCallbacks g_importCallbacks = {
-    &main_document_parsed,
-    &import_import_parsed
-};
-
 // ==========================================================
 static int
 check_filename(const char* filename, const char* package, buffer_type* name)
@@ -256,8 +248,7 @@
             user_data_type* p = (user_data_type*)items;
             err |= check_filename(filename, p->package, &p->name);
         }
-        else if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER) {
             interface_type* c = (interface_type*)items;
             err |= check_filename(filename, c->package, &c->name);
         }
@@ -308,11 +299,9 @@
         if (items->item_type == USER_DATA_TYPE) {
             user_data_type* p = (user_data_type*)items;
             type = new UserDataType(p->package ? p->package : "", p->name.data,
-                    false, ((p->flattening_methods & PARCELABLE_DATA) != 0),
-                    ((p->flattening_methods & RPC_DATA) != 0), filename, p->name.lineno);
+                    false, p->parcelable, filename, p->name.lineno);
         }
-        else if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        else if (items->item_type == INTERFACE_TYPE_BINDER) {
             interface_type* c = (interface_type*)items;
             type = new InterfaceType(c->package ? c->package : "",
                             c->name.data, false, c->oneway,
@@ -336,30 +325,17 @@
                 string name = c->name.data;
                 name += ".Stub";
                 Type* stub = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
+                                        name, Type::GENERATED, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(stub);
 
                 name = c->name.data;
                 name += ".Stub.Proxy";
                 Type* proxy = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
+                                        name, Type::GENERATED, false, false,
                                         filename, c->name.lineno);
                 NAMES.Add(proxy);
             }
-            else if (items->item_type == INTERFACE_TYPE_RPC) {
-                // for interfaces, also add the service base type, we don't
-                // bother checking these for duplicates, because the parser
-                // won't let us do it.
-                interface_type* c = (interface_type*)items;
-
-                string name = c->name.data;
-                name += ".ServiceBase";
-                Type* base = new Type(c->package ? c->package : "",
-                                        name, Type::GENERATED, false, false, false,
-                                        filename, c->name.lineno);
-                NAMES.Add(base);
-            }
         } else {
             if (old->Kind() == Type::BUILT_IN) {
                 fprintf(stderr, "%s:%d attempt to redefine built in class %s\n",
@@ -411,7 +387,7 @@
 }
 
 static int
-check_method(const char* filename, int kind, method_type* m)
+check_method(const char* filename, method_type* m)
 {
     int err = 0;
 
@@ -424,19 +400,10 @@
         return err;
     }
 
-    if (returnType == EVENT_FAKE_TYPE) {
-        if (kind != INTERFACE_TYPE_RPC) {
-            fprintf(stderr, "%s:%d event methods only supported for rpc interfaces\n",
-                    filename, m->type.type.lineno);
-            err = 1;
-        }
-    } else {
-        if (!(kind == INTERFACE_TYPE_BINDER ? returnType->CanWriteToParcel()
-                    : returnType->CanWriteToRpcData())) {
-            fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
+    if (!returnType->CanWriteToParcel()) {
+        fprintf(stderr, "%s:%d return type %s can't be marshalled.\n", filename,
                         m->type.type.lineno, m->type.type.data);
-            err = 1;
-        }
+        err = 1;
     }
 
     if (m->type.dimension > 0 && !returnType->CanBeArray()) {
@@ -469,30 +436,13 @@
             goto next;
         }
 
-        if (t == EVENT_FAKE_TYPE) {
-            fprintf(stderr, "%s:%d parameter %s (%d) event can not be used as a parameter %s\n",
-                    filename, m->type.type.lineno, arg->name.data, index,
-                    arg->type.type.data);
-            err = 1;
-            goto next;
-        }
-        
-        if (!(kind == INTERFACE_TYPE_BINDER ? t->CanWriteToParcel() : t->CanWriteToRpcData())) {
+        if (!t->CanWriteToParcel()) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can't be marshalled.\n",
                         filename, m->type.type.lineno, index,
                         arg->type.type.data, arg->name.data);
             err = 1;
         }
 
-        if (returnType == EVENT_FAKE_TYPE
-                && convert_direction(arg->direction.data) != IN_PARAMETER) {
-            fprintf(stderr, "%s:%d parameter %d: '%s %s' All paremeters on events must be 'in'.\n",
-                    filename, m->type.type.lineno, index,
-                    arg->type.type.data, arg->name.data);
-            err = 1;
-            goto next;
-        }
-
         if (arg->direction.data == NULL
                 && (arg->type.dimension != 0 || t->CanBeOutParameter())) {
             fprintf(stderr, "%s:%d parameter %d: '%s %s' can be an out"
@@ -554,8 +504,7 @@
     int err = 0;
     while (items) {
         // (nothing to check for USER_DATA_TYPE)
-        if (items->item_type == INTERFACE_TYPE_BINDER
-                || items->item_type == INTERFACE_TYPE_RPC) {
+        if (items->item_type == INTERFACE_TYPE_BINDER) {
             map<string,method_type*> methodNames;
             interface_type* c = (interface_type*)items;
 
@@ -564,7 +513,7 @@
                 if (member->item_type == METHOD_TYPE) {
                     method_type* m = (method_type*)member;
 
-                    err |= check_method(filename, items->item_type, m);
+                    err |= check_method(filename, m);
 
                     // prevent duplicate methods
                     if (methodNames.find(m->name.data) == methodNames.end()) {
@@ -605,9 +554,6 @@
         if (next->item_type == INTERFACE_TYPE_BINDER) {
             lineno = ((interface_type*)next)->interface_token.lineno;
         }
-        else if (next->item_type == INTERFACE_TYPE_RPC) {
-            lineno = ((interface_type*)next)->interface_token.lineno;
-        }
         fprintf(stderr, "%s:%d aidl can only handle one interface per file\n",
                             filename, lineno);
         return 1;
@@ -617,9 +563,9 @@
         *onlyParcelable = true;
         if (options.failOnParcelable) {
             fprintf(stderr, "%s:%d aidl can only generate code for interfaces, not"
-                            " parcelables or flattenables,\n", filename,
+                            " parcelables,\n", filename,
                             ((user_data_type*)items)->keyword_token.lineno);
-            fprintf(stderr, "%s:%d .aidl files that only declare parcelables or flattenables"
+            fprintf(stderr, "%s:%d .aidl files that only declare parcelables"
                             "may not go in the Makefile.\n", filename,
                             ((user_data_type*)items)->keyword_token.lineno);
             return 1;
@@ -656,7 +602,7 @@
         slash = "";
     }
 
-    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+    if (items->item_type == INTERFACE_TYPE_BINDER) {
         fprintf(to, "%s: \\\n", options.outputFileName.c_str());
     } else {
         // parcelable: there's no output file.
@@ -730,7 +676,7 @@
 generate_outputFileName(const Options& options, const document_item_type* items)
 {
     // items has already been checked to have only one interface.
-    if (items->item_type == INTERFACE_TYPE_BINDER || items->item_type == INTERFACE_TYPE_RPC) {
+    if (items->item_type == INTERFACE_TYPE_BINDER) {
         interface_type* type = (interface_type*)items;
 
         return generate_outputFileName2(options, type->name, type->package);
@@ -817,22 +763,7 @@
             parcl->name.data = strdup(classname);
             parcl->semicolon_token.lineno = lineno;
             parcl->semicolon_token.data = strdup(";");
-            parcl->flattening_methods = PARCELABLE_DATA;
-            doc = (document_item_type*)parcl;
-        }
-        else if (0 == strcmp("flattenable", type)) {
-            user_data_type* parcl = (user_data_type*)malloc(
-                    sizeof(user_data_type));
-            memset(parcl, 0, sizeof(user_data_type));
-            parcl->document_item.item_type = USER_DATA_TYPE;
-            parcl->keyword_token.lineno = lineno;
-            parcl->keyword_token.data = strdup(type);
-            parcl->package = packagename ? strdup(packagename) : NULL;
-            parcl->name.lineno = lineno;
-            parcl->name.data = strdup(classname);
-            parcl->semicolon_token.lineno = lineno;
-            parcl->semicolon_token.data = strdup(";");
-            parcl->flattening_methods = RPC_DATA;
+            parcl->parcelable = true;
             doc = (document_item_type*)parcl;
         }
         else if (0 == strcmp("interface", type)) {
@@ -938,7 +869,7 @@
 }
 
 // ==========================================================
-static int
+int
 compile_aidl(Options& options)
 {
     int err = 0, N;
@@ -1068,7 +999,7 @@
     return err;
 }
 
-static int
+int
 preprocess_aidl(const Options& options)
 {
     vector<string> lines;
@@ -1086,12 +1017,9 @@
         string line;
         if (doc->item_type == USER_DATA_TYPE) {
             user_data_type* parcelable = (user_data_type*)doc;
-            if ((parcelable->flattening_methods & PARCELABLE_DATA) != 0) {
+            if (parcelable->parcelable) {
                 line = "parcelable ";
             }
-            if ((parcelable->flattening_methods & RPC_DATA) != 0) {
-                line = "flattenable ";
-            }
             if (parcelable->package) {
                 line += parcelable->package;
                 line += '.';
@@ -1140,24 +1068,3 @@
     close(fd);
     return 0;
 }
-
-// ==========================================================
-int
-main(int argc, const char **argv)
-{
-    Options options;
-    int result = parse_options(argc, argv, &options);
-    if (result) {
-        return result;
-    }
-
-    switch (options.task)
-    {
-        case COMPILE_AIDL:
-            return compile_aidl(options);
-        case PREPROCESS_AIDL:
-            return preprocess_aidl(options);
-    }
-    fprintf(stderr, "aidl: internal error\n");
-    return 1;
-}
diff --git a/tools/aidl/aidl.h b/tools/aidl/aidl.h
new file mode 100644
index 0000000..98b15f3
--- /dev/null
+++ b/tools/aidl/aidl.h
@@ -0,0 +1,9 @@
+#ifndef AIDL_AIDL_H_
+#define AIDL_AIDL_H_
+
+#include "options.h"
+
+int compile_aidl(Options& options);
+int preprocess_aidl(const Options& options);
+
+#endif  // AIDL_AIDL_H_
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index de1370c..a3b1efc 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
-#define DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#ifndef AIDL_AIDL_LANGUAGE_H_
+#define AIDL_AIDL_LANGUAGE_H_
 
 
 typedef enum {
@@ -68,8 +68,7 @@
 
 enum {
     USER_DATA_TYPE = 12,
-    INTERFACE_TYPE_BINDER,
-    INTERFACE_TYPE_RPC
+    INTERFACE_TYPE_BINDER
 };
 
 typedef struct document_item_type {
@@ -78,19 +77,13 @@
 } document_item_type;
 
 
-// for user_data_type.flattening_methods
-enum {
-    PARCELABLE_DATA = 0x1,
-    RPC_DATA = 0x2
-};
-
 typedef struct user_data_type {
     document_item_type document_item;
     buffer_type keyword_token; // only the first one
     char* package;
     buffer_type name;
     buffer_type semicolon_token;
-    int flattening_methods;
+    bool parcelable;
 } user_data_type;
 
 typedef struct interface_type {
@@ -169,4 +162,4 @@
 #endif
 
 
-#endif // DEVICE_TOOLS_AIDL_AIDL_LANGUAGE_H
+#endif // AIDL_AIDL_LANGUAGE_H_
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 3d33e7a..aa42f2e 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -83,8 +83,6 @@
     /* keywords */
 parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
 interface       { SET_BUFFER(INTERFACE); return INTERFACE; }
-flattenable     { SET_BUFFER(FLATTENABLE); return FLATTENABLE; }
-rpc             { SET_BUFFER(INTERFACE); return RPC; }
 in              { SET_BUFFER(IN); return IN; }
 out             { SET_BUFFER(OUT); return OUT; }
 inout           { SET_BUFFER(INOUT); return INOUT; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index 9b40d28..9c5d10e 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -20,8 +20,6 @@
 %token ARRAY
 %token PARCELABLE
 %token INTERFACE
-%token FLATTENABLE
-%token RPC
 %token IN
 %token OUT
 %token INOUT
@@ -88,7 +86,7 @@
                                                         b->name = $2.buffer;
                                                         b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
                                                         b->semicolon_token = $3.buffer;
-                                                        b->flattening_methods = PARCELABLE_DATA;
+                                                        b->parcelable = true;
                                                         $$.user_data = b;
                                                     }
     |   PARCELABLE ';'                              {
@@ -101,28 +99,6 @@
                                                                      g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.user_data = NULL;
                                                     }
-    |   FLATTENABLE IDENTIFIER ';'                  {
-                                                        user_data_type* b = (user_data_type*)malloc(sizeof(user_data_type));
-                                                        b->document_item.item_type = USER_DATA_TYPE;
-                                                        b->document_item.next = NULL;
-                                                        b->keyword_token = $1.buffer;
-                                                        b->name = $2.buffer;
-                                                        b->package = g_currentPackage ? strdup(g_currentPackage) : NULL;
-                                                        b->semicolon_token = $3.buffer;
-                                                        b->flattening_methods = PARCELABLE_DATA | RPC_DATA;
-                                                        $$.user_data = b;
-                                                    }
-    |   FLATTENABLE ';'                             {
-                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name.\n",
-                                                                     g_currentFilename, $1.buffer.lineno);
-                                                        $$.user_data = NULL;
-                                                    }
-    |   FLATTENABLE error ';'                       {
-                                                        fprintf(stderr, "%s:%d syntax error in flattenable declaration. Expected type name, saw \"%s\".\n",
-                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
-                                                        $$.user_data = NULL;
-                                                    }
-
     ;
 
 interface_header:
@@ -146,21 +122,6 @@
                                                         c->comments_token = &c->oneway_token;
                                                         $$.interface_obj = c;
                                                    }
-    |   RPC                                        {
-                                                        interface_type* c = (interface_type*)malloc(sizeof(interface_type));
-                                                        c->document_item.item_type = INTERFACE_TYPE_RPC;
-                                                        c->document_item.next = NULL;
-                                                        c->interface_token = $1.buffer;
-                                                        c->oneway = false;
-                                                        memset(&c->oneway_token, 0, sizeof(buffer_type));
-                                                        c->comments_token = &c->interface_token;
-                                                        $$.interface_obj = c;
-                                                   }
-    ;
-
-interface_keywords:
-        INTERFACE
-    |   RPC
     ;
 
 interface_decl:
@@ -173,12 +134,12 @@
                                                         c->close_brace_token = $5.buffer;
                                                         $$.interface_obj = c;
                                                     }
-    |   interface_keywords error '{' interface_items '}'     {
+    |   INTERFACE error '{' interface_items '}'     {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
                                                     }
-    |   interface_keywords error '}'                {
+    |   INTERFACE error '}'                {
                                                         fprintf(stderr, "%s:%d: syntax error in interface declaration.  Expected type name, saw \"%s\"\n",
                                                                     g_currentFilename, $2.buffer.lineno, $2.buffer.data);
                                                         $$.document_item = NULL;
diff --git a/tools/aidl/generate_java.cpp b/tools/aidl/generate_java.cpp
index 9e57407..1509340 100644
--- a/tools/aidl/generate_java.cpp
+++ b/tools/aidl/generate_java.cpp
@@ -66,9 +66,6 @@
     if (iface->document_item.item_type == INTERFACE_TYPE_BINDER) {
         cl = generate_binder_interface_class(iface);
     }
-    else if (iface->document_item.item_type == INTERFACE_TYPE_RPC) {
-        cl = generate_rpc_interface_class(iface);
-    }
 
     Document* document = new Document;
         document->comment = "";
diff --git a/tools/aidl/generate_java.h b/tools/aidl/generate_java.h
index 4bfcfeb..4e79743 100644
--- a/tools/aidl/generate_java.h
+++ b/tools/aidl/generate_java.h
@@ -1,5 +1,5 @@
-#ifndef GENERATE_JAVA_H
-#define GENERATE_JAVA_H
+#ifndef AIDL_GENERATE_JAVA_H_
+#define AIDL_GENERATE_JAVA_H_
 
 #include "aidl_language.h"
 #include "AST.h"
@@ -12,7 +12,6 @@
                 interface_type* iface);
 
 Class* generate_binder_interface_class(const interface_type* iface);
-Class* generate_rpc_interface_class(const interface_type* iface);
 
 string gather_comments(extra_text_type* extra);
 string append(const char* a, const char* b);
@@ -29,5 +28,5 @@
     int m_index;
 };
 
-#endif // GENERATE_JAVA_H
+#endif // AIDL_GENERATE_JAVA_H_
 
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
deleted file mode 100644
index 5e4dacc..0000000
--- a/tools/aidl/generate_java_rpc.cpp
+++ /dev/null
@@ -1,1001 +0,0 @@
-#include "generate_java.h"
-#include "Type.h"
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
-        "Context", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
-        "EventListener", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
-        "EventListener.Listener", Type::BUILT_IN, false, false, false);
-Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
-        Type::BUILT_IN, false, false, false);
-Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
-        Type::BUILT_IN, false, false, false);
-// TODO: Just use Endpoint, so this works for all endpoints.
-Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
-        "EndpointInfo", true, __FILE__, __LINE__);
-Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
-        true, __FILE__, __LINE__);
-Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
-        Type::BUILT_IN, false, false, false);
-Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
-        __FILE__, __LINE__);
-
-static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
-        Variable* v, Variable* data, Variable** cl);
-static void generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from);
-static void generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v,
-        Variable* data);
-
-static string
-format_int(int n)
-{
-    char str[20];
-    sprintf(str, "%d", n);
-    return string(str);
-}
-
-static string
-class_name_leaf(const string& str)
-{
-    string::size_type pos = str.rfind('.');
-    if (pos == string::npos) {
-        return str;
-    } else {
-        return string(str, pos+1);
-    }
-}
-
-static string
-results_class_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "On");
-    return str;
-}
-
-static string
-results_method_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "on");
-    return str;
-}
-
-static string
-push_method_name(const string& n)
-{
-    string str = n;
-    str[0] = toupper(str[0]);
-    str.insert(0, "push");
-    return str;
-}
-
-// =================================================
-class DispatcherClass : public Class
-{
-public:
-    DispatcherClass(const interface_type* iface, Expression* target);
-    virtual ~DispatcherClass();
-
-    void AddMethod(const method_type* method);
-    void DoneWithMethods();
-
-    Method* processMethod;
-    Variable* actionParam;
-    Variable* requestParam;
-    Variable* rpcContextParam;
-    Variable* errorParam;
-    Variable* requestData;
-    Variable* resultData;
-    IfStatement* dispatchIfStatement;
-    Expression* targetExpression;
-
-private:
-    void generate_process();
-};
-
-DispatcherClass::DispatcherClass(const interface_type* iface, Expression* target)
-    :Class(),
-     dispatchIfStatement(NULL),
-     targetExpression(target)
-{
-    generate_process();
-}
-
-DispatcherClass::~DispatcherClass()
-{
-}
-
-void
-DispatcherClass::generate_process()
-{
-    // byte[] process(String action, byte[] params, RpcContext context, RpcError status)
-    this->processMethod = new Method;
-        this->processMethod->modifiers = PUBLIC;
-        this->processMethod->returnType = BYTE_TYPE;
-        this->processMethod->returnTypeDimension = 1;
-        this->processMethod->name = "process";
-        this->processMethod->statements = new StatementBlock;
-
-    this->actionParam = new Variable(STRING_TYPE, "action");
-    this->processMethod->parameters.push_back(this->actionParam);
-
-    this->requestParam = new Variable(BYTE_TYPE, "requestParam", 1);
-    this->processMethod->parameters.push_back(this->requestParam);
-
-    this->rpcContextParam = new Variable(RPC_CONTEXT_TYPE, "context", 0);
-    this->processMethod->parameters.push_back(this->rpcContextParam);    
-
-    this->errorParam = new Variable(RPC_ERROR_TYPE, "errorParam", 0);
-    this->processMethod->parameters.push_back(this->errorParam);
-
-    this->requestData = new Variable(RPC_DATA_TYPE, "request");
-    this->processMethod->statements->Add(new VariableDeclaration(requestData,
-                new NewExpression(RPC_DATA_TYPE, 1, this->requestParam)));
-
-    this->resultData = new Variable(RPC_DATA_TYPE, "resultData");
-    this->processMethod->statements->Add(new VariableDeclaration(this->resultData,
-                NULL_VALUE));
-}
-
-void
-DispatcherClass::AddMethod(const method_type* method)
-{
-    arg_type* arg;
-
-    // The if/switch statement
-    IfStatement* ifs = new IfStatement();
-        ifs->expression = new MethodCall(new StringLiteralExpression(method->name.data), "equals",
-                1, this->actionParam);
-    StatementBlock* block = ifs->statements = new StatementBlock;
-    if (this->dispatchIfStatement == NULL) {
-        this->dispatchIfStatement = ifs;
-        this->processMethod->statements->Add(dispatchIfStatement);
-    } else {
-        this->dispatchIfStatement->elseif = ifs;
-        this->dispatchIfStatement = ifs;
-    }
-    
-    // The call to decl (from above)
-    MethodCall* realCall = new MethodCall(this->targetExpression, method->name.data);
-
-    // args
-    Variable* classLoader = NULL;
-    VariableFactory stubArgs("_arg");
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(t);
-        v->dimension = arg->type.dimension;
-
-        // Unmarshall the parameter
-        block->Add(new VariableDeclaration(v));
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            generate_create_from_data(t, block, arg->name.data, v,
-                    this->requestData, &classLoader);
-        } else {
-            if (arg->type.dimension == 0) {
-                block->Add(new Assignment(v, new NewExpression(v->type)));
-            }
-            else if (arg->type.dimension == 1) {
-                generate_new_array(v->type, block, v, this->requestData);
-            }
-            else {
-                fprintf(stderr, "aidl:internal error %s:%d\n", __FILE__,
-                        __LINE__);
-            }
-        }
-
-        // Add that parameter to the method call
-        realCall->arguments.push_back(v);
-
-        arg = arg->next;
-    }
-
-    // Add a final parameter: RpcContext. Contains data about
-    // incoming request (e.g., certificate)
-    realCall->arguments.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-
-    Type* returnType = NAMES.Search(method->type.type.data);
-    if (returnType == EVENT_FAKE_TYPE) {
-        returnType = VOID_TYPE;
-    }
-    
-    // the real call
-    bool first = true;
-    Variable* _result = NULL;
-    if (returnType == VOID_TYPE) {
-        block->Add(realCall);
-    } else {
-        _result = new Variable(returnType, "_result",
-                                method->type.dimension);
-        block->Add(new VariableDeclaration(_result, realCall));
-
-        // need the result RpcData
-        if (first) {
-            block->Add(new Assignment(this->resultData,
-                        new NewExpression(RPC_DATA_TYPE)));
-            first = false;
-        }
-
-        // marshall the return value
-        generate_write_to_data(returnType, block,
-                new StringLiteralExpression("_result"), _result, this->resultData);
-    }
-
-    // out parameters
-    int i = 0;
-    arg = method->args;
-    while (arg != NULL) {
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = stubArgs.Get(i++);
-
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            // need the result RpcData
-            if (first) {
-                block->Add(new Assignment(this->resultData, new NewExpression(RPC_DATA_TYPE)));
-                first = false;
-            }
-
-            generate_write_to_data(t, block, new StringLiteralExpression(arg->name.data),
-                    v, this->resultData);
-        }
-
-        arg = arg->next;
-    }
-}
-
-void
-DispatcherClass::DoneWithMethods()
-{
-    if (this->dispatchIfStatement == NULL) {
-        return;
-    }
-
-    this->elements.push_back(this->processMethod);
-
-    IfStatement* fallthrough = new IfStatement();
-        fallthrough->statements = new StatementBlock;
-        fallthrough->statements->Add(new ReturnStatement(
-                    new MethodCall(SUPER_VALUE, "process", 4, 
-                    this->actionParam, this->requestParam, 
-                    this->rpcContextParam,
-                    this->errorParam)));
-    this->dispatchIfStatement->elseif = fallthrough;
-    IfStatement* s = new IfStatement;
-        s->statements = new StatementBlock;
-    this->processMethod->statements->Add(s);
-    s->expression = new Comparison(this->resultData, "!=", NULL_VALUE);
-    s->statements->Add(new ReturnStatement(new MethodCall(this->resultData, "serialize")));
-    s->elseif = new IfStatement;
-    s = s->elseif;
-    s->statements->Add(new ReturnStatement(NULL_VALUE));
-}
-
-// =================================================
-class RpcProxyClass : public Class
-{
-public:
-    RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType);
-    virtual ~RpcProxyClass();
-
-    Variable* endpoint;
-    Variable* broker;
-
-private:
-    void generate_ctor();
-    void generate_get_endpoint_info();
-};
-
-RpcProxyClass::RpcProxyClass(const interface_type* iface, InterfaceType* interfaceType)
-    :Class()
-{
-    this->comment = gather_comments(iface->comments_token->extra);
-    this->modifiers = PUBLIC;
-    this->what = Class::CLASS;
-    this->type = interfaceType;
-
-    // broker
-    this->broker = new Variable(RPC_BROKER_TYPE, "_broker");
-    this->elements.push_back(new Field(PRIVATE, this->broker));
-    // endpoint
-    this->endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "_endpoint");
-    this->elements.push_back(new Field(PRIVATE, this->endpoint));
-
-    // methods
-    generate_ctor();
-    generate_get_endpoint_info();
-}
-
-RpcProxyClass::~RpcProxyClass()
-{
-}
-
-void
-RpcProxyClass::generate_ctor()
-{
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-    Variable* endpoint = new Variable(RPC_ENDPOINT_INFO_TYPE, "endpoint");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(endpoint);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new Assignment(this->broker, broker));
-    ctor->statements->Add(new Assignment(this->endpoint, endpoint));
-}
-
-void
-RpcProxyClass::generate_get_endpoint_info()
-{
-    Method* get = new Method;
-    get->modifiers = PUBLIC;
-    get->returnType = RPC_ENDPOINT_INFO_TYPE;
-    get->name = "getEndpointInfo";
-    get->statements = new StatementBlock;
-    this->elements.push_back(get);
-
-    get->statements->Add(new ReturnStatement(this->endpoint));
-}
-
-// =================================================
-class EventListenerClass : public DispatcherClass
-{
-public:
-    EventListenerClass(const interface_type* iface, Type* listenerType);
-    virtual ~EventListenerClass();
-
-    Variable* _listener;
-
-private:
-    void generate_ctor();
-};
-
-Expression*
-generate_get_listener_expression(Type* cast)
-{
-    return new Cast(cast, new MethodCall(THIS_VALUE, "getView"));
-}
-
-EventListenerClass::EventListenerClass(const interface_type* iface, Type* listenerType)
-    :DispatcherClass(iface, new FieldVariable(THIS_VALUE, "_listener"))
-{
-    this->modifiers = PRIVATE;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".Presenter"),
-                        Type::GENERATED, false, false, false);
-    this->extends = PRESENTER_BASE_TYPE;
-
-    this->_listener = new Variable(listenerType, "_listener");
-    this->elements.push_back(new Field(PRIVATE, this->_listener));
-
-    // methods
-    generate_ctor();
-}
-
-EventListenerClass::~EventListenerClass()
-{
-}
-
-void
-EventListenerClass::generate_ctor()
-{
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-    Variable* listener = new Variable(this->_listener->type, "listener");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(listener);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new MethodCall("super", 2, broker, listener));
-    ctor->statements->Add(new Assignment(this->_listener, listener));
-}
-
-// =================================================
-class ListenerClass : public Class
-{
-public:
-    ListenerClass(const interface_type* iface);
-    virtual ~ListenerClass();
-
-    bool needed;
-
-private:
-    void generate_ctor();
-};
-
-ListenerClass::ListenerClass(const interface_type* iface)
-    :Class(),
-     needed(false)
-{
-    this->comment = "/** Extend this to listen to the events from this class. */";
-    this->modifiers = STATIC | PUBLIC ;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".Listener"),
-                        Type::GENERATED, false, false, false);
-    this->extends = PRESENTER_LISTENER_BASE_TYPE;
-}
-
-ListenerClass::~ListenerClass()
-{
-}
-
-// =================================================
-class EndpointBaseClass : public DispatcherClass
-{
-public:
-    EndpointBaseClass(const interface_type* iface);
-    virtual ~EndpointBaseClass();
-
-    bool needed;
-
-private:
-    void generate_ctor();
-};
-
-EndpointBaseClass::EndpointBaseClass(const interface_type* iface)
-    :DispatcherClass(iface, THIS_VALUE),
-     needed(false)
-{
-    this->comment = "/** Extend this to implement a link service. */";
-    this->modifiers = STATIC | PUBLIC | ABSTRACT;
-    this->what = Class::CLASS;
-    this->type = new Type(iface->package ? iface->package : "",
-                        append(iface->name.data, ".EndpointBase"),
-                        Type::GENERATED, false, false, false);
-    this->extends = RPC_CONNECTOR_TYPE;
-
-    // methods
-    generate_ctor();
-}
-
-EndpointBaseClass::~EndpointBaseClass()
-{
-}
-
-void
-EndpointBaseClass::generate_ctor()
-{
-    Variable* container = new Variable(RPC_CONTAINER_TYPE, "container");
-    Variable* broker = new Variable(RPC_BROKER_TYPE, "broker");
-	Variable* place = new Variable(PLACE_INFO_TYPE, "placeInfo");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(container);
-        ctor->parameters.push_back(broker);
-        ctor->parameters.push_back(place);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new MethodCall("super", 3, container, broker, place));
-}
-
-// =================================================
-class ResultDispatcherClass : public Class
-{
-public:
-    ResultDispatcherClass();
-    virtual ~ResultDispatcherClass();
-
-    void AddMethod(int index, const string& name, Method** method, Variable** param);
-
-    bool needed;
-    Variable* methodId;
-    Variable* callback;
-    Method* onResultMethod;
-    Variable* resultParam;
-    SwitchStatement* methodSwitch;
-
-private:
-    void generate_ctor();
-    void generate_onResult();
-};
-
-ResultDispatcherClass::ResultDispatcherClass()
-    :Class(),
-     needed(false)
-{
-    this->modifiers = PRIVATE | FINAL;
-    this->what = Class::CLASS;
-    this->type = new Type("_ResultDispatcher", Type::GENERATED, false, false, false);
-    this->interfaces.push_back(RPC_RESULT_HANDLER_TYPE);
-
-    // methodId
-    this->methodId = new Variable(INT_TYPE, "methodId");
-    this->elements.push_back(new Field(PRIVATE, this->methodId));
-    this->callback = new Variable(OBJECT_TYPE, "callback");
-    this->elements.push_back(new Field(PRIVATE, this->callback));
-
-    // methods
-    generate_ctor();
-    generate_onResult();
-}
-
-ResultDispatcherClass::~ResultDispatcherClass()
-{
-}
-
-void
-ResultDispatcherClass::generate_ctor()
-{
-    Variable* methodIdParam = new Variable(INT_TYPE, "methId");
-    Variable* callbackParam = new Variable(OBJECT_TYPE, "cbObj");
-    Method* ctor = new Method;
-        ctor->modifiers = PUBLIC;
-        ctor->name = class_name_leaf(this->type->Name());
-        ctor->statements = new StatementBlock;
-        ctor->parameters.push_back(methodIdParam);
-        ctor->parameters.push_back(callbackParam);
-    this->elements.push_back(ctor);
-
-    ctor->statements->Add(new Assignment(this->methodId, methodIdParam));
-    ctor->statements->Add(new Assignment(this->callback, callbackParam));
-}
-
-void
-ResultDispatcherClass::generate_onResult()
-{
-    this->onResultMethod = new Method;
-        this->onResultMethod->modifiers = PUBLIC;
-        this->onResultMethod->returnType = VOID_TYPE;
-        this->onResultMethod->returnTypeDimension = 0;
-        this->onResultMethod->name = "onResult";
-        this->onResultMethod->statements = new StatementBlock;
-    this->elements.push_back(this->onResultMethod);
-
-    this->resultParam = new Variable(BYTE_TYPE, "result", 1);
-    this->onResultMethod->parameters.push_back(this->resultParam);
-
-    this->methodSwitch = new SwitchStatement(this->methodId);
-    this->onResultMethod->statements->Add(this->methodSwitch);
-}
-
-void
-ResultDispatcherClass::AddMethod(int index, const string& name, Method** method, Variable** param)
-{
-    Method* m = new Method;
-        m->modifiers = PUBLIC;
-        m->returnType = VOID_TYPE;
-        m->returnTypeDimension = 0;
-        m->name = name;
-        m->statements = new StatementBlock;
-    *param = new Variable(BYTE_TYPE, "result", 1);
-    m->parameters.push_back(*param);
-    this->elements.push_back(m);
-    *method = m;
-
-    Case* c = new Case(format_int(index));
-    c->statements->Add(new MethodCall(new LiteralExpression("this"), name, 1, this->resultParam));
-    c->statements->Add(new Break());
-
-    this->methodSwitch->cases.push_back(c);
-}
-
-// =================================================
-static void
-generate_new_array(Type* t, StatementBlock* addTo, Variable* v, Variable* from)
-{
-    fprintf(stderr, "aidl: implement generate_new_array %s:%d\n", __FILE__, __LINE__);
-    exit(1);
-}
-
-static void
-generate_create_from_data(Type* t, StatementBlock* addTo, const string& key, Variable* v,
-                            Variable* data, Variable** cl)
-{
-    Expression* k = new StringLiteralExpression(key);
-    if (v->dimension == 0) {
-        t->CreateFromRpcData(addTo, k, v, data, cl);
-    }
-    if (v->dimension == 1) {
-        //t->ReadArrayFromRpcData(addTo, v, data, cl);
-        fprintf(stderr, "aidl: implement generate_create_from_data for arrays%s:%d\n",
-                __FILE__, __LINE__);
-    }
-}
-
-static void
-generate_write_to_data(Type* t, StatementBlock* addTo, Expression* k, Variable* v, Variable* data)
-{
-    if (v->dimension == 0) {
-        t->WriteToRpcData(addTo, k, v, data, 0);
-    }
-    if (v->dimension == 1) {
-        //t->WriteArrayToParcel(addTo, v, data);
-        fprintf(stderr, "aidl: implement generate_write_to_data for arrays%s:%d\n",
-                __FILE__, __LINE__);
-    }
-}
-
-// =================================================
-static Type*
-generate_results_method(const method_type* method, RpcProxyClass* proxyClass)
-{
-    arg_type* arg;
-
-    string resultsMethodName = results_method_name(method->name.data);
-    Type* resultsInterfaceType = new Type(results_class_name(method->name.data),
-            Type::GENERATED, false, false, false);
-
-    if (!method->oneway) {
-        Class* resultsClass = new Class;
-            resultsClass->modifiers = STATIC | PUBLIC;
-            resultsClass->what = Class::INTERFACE;
-            resultsClass->type = resultsInterfaceType;
-
-        Method* resultMethod = new Method;
-            resultMethod->comment = gather_comments(method->comments_token->extra);
-            resultMethod->modifiers = PUBLIC;
-            resultMethod->returnType = VOID_TYPE;
-            resultMethod->returnTypeDimension = 0;
-            resultMethod->name = resultsMethodName;
-        if (0 != strcmp("void", method->type.type.data)) {
-            resultMethod->parameters.push_back(new Variable(NAMES.Search(method->type.type.data),
-                        "_result", method->type.dimension));
-        }
-        arg = method->args;
-        while (arg != NULL) {
-            if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-                resultMethod->parameters.push_back(new Variable(
-                                    NAMES.Search(arg->type.type.data), arg->name.data,
-                                    arg->type.dimension));
-            }
-            arg = arg->next;
-        }
-        resultsClass->elements.push_back(resultMethod);
-
-        if (resultMethod->parameters.size() > 0) {
-            proxyClass->elements.push_back(resultsClass);
-            return resultsInterfaceType;
-        } 
-    }
-    //delete resultsInterfaceType;
-    return NULL;
-}
-
-static void
-generate_proxy_method(const method_type* method, RpcProxyClass* proxyClass,
-        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
-{
-    arg_type* arg;
-    Method* proxyMethod = new Method;
-        proxyMethod->comment = gather_comments(method->comments_token->extra);
-        proxyMethod->modifiers = PUBLIC;
-        proxyMethod->returnType = VOID_TYPE;
-        proxyMethod->returnTypeDimension = 0;
-        proxyMethod->name = method->name.data;
-        proxyMethod->statements = new StatementBlock;
-    proxyClass->elements.push_back(proxyMethod);
-
-    // The local variables
-    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
-    proxyMethod->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
-
-    // Add the arguments
-    arg = method->args;
-    while (arg != NULL) {
-        if (convert_direction(arg->direction.data) & IN_PARAMETER) {
-            // Function signature
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-            proxyMethod->parameters.push_back(v);
-
-            // Input parameter marshalling
-            generate_write_to_data(t, proxyMethod->statements,
-                    new StringLiteralExpression(arg->name.data), v, _data);
-        }
-        arg = arg->next;
-    }
-
-    // If there is a results interface for this class
-    Expression* resultParameter;
-    if (resultsInterfaceType != NULL) {
-        // Result interface parameter
-        Variable* resultListener = new Variable(resultsInterfaceType, "_result");
-        proxyMethod->parameters.push_back(resultListener);
-
-        // Add the results dispatcher callback
-        resultsDispatcherClass->needed = true;
-        resultParameter = new NewExpression(resultsDispatcherClass->type, 2,
-                new LiteralExpression(format_int(index)), resultListener);
-    } else {
-        resultParameter = NULL_VALUE;
-    }
-
-    // All proxy methods take an error parameter
-    Variable* errorListener = new Variable(RPC_ERROR_LISTENER_TYPE, "_errors");
-    proxyMethod->parameters.push_back(errorListener);
-
-    // Call the broker
-    proxyMethod->statements->Add(new MethodCall(new FieldVariable(THIS_VALUE, "_broker"),
-                "sendRpc", 5,
-                proxyClass->endpoint,
-                new StringLiteralExpression(method->name.data),
-                new MethodCall(_data, "serialize"),
-                resultParameter,
-                errorListener));
-}
-
-static void
-generate_result_dispatcher_method(const method_type* method,
-        ResultDispatcherClass* resultsDispatcherClass, Type* resultsInterfaceType, int index)
-{
-    arg_type* arg;
-    Method* dispatchMethod;
-    Variable* dispatchParam;
-    resultsDispatcherClass->AddMethod(index, method->name.data, &dispatchMethod, &dispatchParam);
-
-    Variable* classLoader = NULL;
-    Variable* resultData = new Variable(RPC_DATA_TYPE, "resultData");
-    dispatchMethod->statements->Add(new VariableDeclaration(resultData,
-                new NewExpression(RPC_DATA_TYPE, 1, dispatchParam)));
-
-    // The callback method itself
-    MethodCall* realCall = new MethodCall(
-            new Cast(resultsInterfaceType, new FieldVariable(THIS_VALUE, "callback")),
-            results_method_name(method->name.data));
-
-    // The return value
-    {
-        Type* t = NAMES.Search(method->type.type.data);
-        if (t != VOID_TYPE) {
-            Variable* rv = new Variable(t, "rv");
-            dispatchMethod->statements->Add(new VariableDeclaration(rv));
-            generate_create_from_data(t, dispatchMethod->statements, "_result", rv,
-                    resultData, &classLoader);
-            realCall->arguments.push_back(rv);
-        }
-    }
-
-    VariableFactory stubArgs("arg");
-    arg = method->args;
-    while (arg != NULL) {
-        if (convert_direction(arg->direction.data) & OUT_PARAMETER) {
-            // Unmarshall the results
-            Type* t = NAMES.Search(arg->type.type.data);
-            Variable* v = stubArgs.Get(t);
-            dispatchMethod->statements->Add(new VariableDeclaration(v));
-
-            generate_create_from_data(t, dispatchMethod->statements, arg->name.data, v,
-                    resultData, &classLoader);
-
-            // Add the argument to the callback
-            realCall->arguments.push_back(v);
-        }
-        arg = arg->next;
-    }
-
-    // Call the callback method
-    IfStatement* ifst = new IfStatement;
-        ifst->expression = new Comparison(new FieldVariable(THIS_VALUE, "callback"), "!=", NULL_VALUE);
-    dispatchMethod->statements->Add(ifst);
-    ifst->statements->Add(realCall);
-}
-
-static void
-generate_regular_method(const method_type* method, RpcProxyClass* proxyClass,
-        EndpointBaseClass* serviceBaseClass, ResultDispatcherClass* resultsDispatcherClass,
-        int index)
-{
-    arg_type* arg;
-
-    // == the callback interface for results ================================
-    // the service base class
-    Type* resultsInterfaceType = generate_results_method(method, proxyClass);
-    
-    // == the method in the proxy class =====================================
-    generate_proxy_method(method, proxyClass, resultsDispatcherClass, resultsInterfaceType, index);
-
-    // == the method in the result dispatcher class =========================
-    if (resultsInterfaceType != NULL) {
-        generate_result_dispatcher_method(method, resultsDispatcherClass, resultsInterfaceType,
-                index);
-    }
-
-    // == The abstract method that the service developers implement ==========
-    Method* decl = new Method;
-        decl->comment = gather_comments(method->comments_token->extra);
-        decl->modifiers = PUBLIC | ABSTRACT;
-        decl->returnType = NAMES.Search(method->type.type.data);
-        decl->returnTypeDimension = method->type.dimension;
-        decl->name = method->name.data;
-    arg = method->args;
-    while (arg != NULL) {
-        decl->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    // Add the default RpcContext param to all methods
-    decl->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-	
-    serviceBaseClass->elements.push_back(decl);
-    
-
-    // == the dispatch method in the service base class ======================
-    serviceBaseClass->AddMethod(method);
-}
-
-static void
-generate_event_method(const method_type* method, RpcProxyClass* proxyClass,
-        EndpointBaseClass* serviceBaseClass, ListenerClass* listenerClass,
-        EventListenerClass* presenterClass, int index)
-{
-    arg_type* arg;
-    listenerClass->needed = true;
-
-    // == the push method in the service base class =========================
-    Method* push = new Method;
-        push->modifiers = PUBLIC;
-        push->name = push_method_name(method->name.data);
-        push->statements = new StatementBlock;
-        push->returnType = VOID_TYPE;
-    serviceBaseClass->elements.push_back(push);
-
-    // The local variables
-    Variable* _data = new Variable(RPC_DATA_TYPE, "_data");
-    push->statements->Add(new VariableDeclaration(_data, new NewExpression(RPC_DATA_TYPE)));
-
-    // Add the arguments
-    arg = method->args;
-    while (arg != NULL) {
-        // Function signature
-        Type* t = NAMES.Search(arg->type.type.data);
-        Variable* v = new Variable(t, arg->name.data, arg->type.dimension);
-        push->parameters.push_back(v);
-
-        // Input parameter marshalling
-        generate_write_to_data(t, push->statements,
-                new StringLiteralExpression(arg->name.data), v, _data);
-
-        arg = arg->next;
-    }
-
-    // Send the notifications
-    push->statements->Add(new MethodCall("pushEvent", 2,
-                new StringLiteralExpression(method->name.data),
-                new MethodCall(_data, "serialize")));
-
-    // == the event callback dispatcher method  ====================================
-    presenterClass->AddMethod(method);
-
-    // == the event method in the listener base class =====================
-    Method* event = new Method;
-        event->modifiers = PUBLIC;
-        event->name = method->name.data;
-        event->statements = new StatementBlock;
-        event->returnType = VOID_TYPE;
-    listenerClass->elements.push_back(event);
-    arg = method->args;
-    while (arg != NULL) {
-        event->parameters.push_back(new Variable(
-                            NAMES.Search(arg->type.type.data), arg->name.data,
-                            arg->type.dimension));
-        arg = arg->next;
-    }
-
-    // Add a final parameter: RpcContext. Contains data about
-    // incoming request (e.g., certificate)
-    event->parameters.push_back(new Variable(RPC_CONTEXT_TYPE, "context", 0));
-}
-
-static void
-generate_listener_methods(RpcProxyClass* proxyClass, Type* presenterType, Type* listenerType)
-{
-    // AndroidAtHomePresenter _presenter;
-    // void startListening(Listener listener) {
-    //     stopListening();
-    //     _presenter = new Presenter(_broker, listener);
-    //     _presenter.startListening(_endpoint);
-    // }
-    // void stopListening() {
-    //     if (_presenter != null) {
-    //         _presenter.stopListening();
-    //     }
-    // }
-
-    Variable* _presenter = new Variable(presenterType, "_presenter");
-    proxyClass->elements.push_back(new Field(PRIVATE, _presenter));
-
-    Variable* listener = new Variable(listenerType, "listener");
-
-    Method* startListeningMethod = new Method;
-        startListeningMethod->modifiers = PUBLIC;
-        startListeningMethod->returnType = VOID_TYPE;
-        startListeningMethod->name = "startListening";
-        startListeningMethod->statements = new StatementBlock;
-        startListeningMethod->parameters.push_back(listener);
-    proxyClass->elements.push_back(startListeningMethod);
-
-    startListeningMethod->statements->Add(new MethodCall(THIS_VALUE, "stopListening"));
-    startListeningMethod->statements->Add(new Assignment(_presenter,
-                new NewExpression(presenterType, 2, proxyClass->broker, listener)));
-    startListeningMethod->statements->Add(new MethodCall(_presenter,
-                "startListening", 1, proxyClass->endpoint));
-
-    Method* stopListeningMethod = new Method;
-        stopListeningMethod->modifiers = PUBLIC;
-        stopListeningMethod->returnType = VOID_TYPE;
-        stopListeningMethod->name = "stopListening";
-        stopListeningMethod->statements = new StatementBlock;
-    proxyClass->elements.push_back(stopListeningMethod);
-
-    IfStatement* ifst = new IfStatement;
-        ifst->expression = new Comparison(_presenter, "!=", NULL_VALUE);
-    stopListeningMethod->statements->Add(ifst);
-
-    ifst->statements->Add(new MethodCall(_presenter, "stopListening"));
-    ifst->statements->Add(new Assignment(_presenter, NULL_VALUE));
-}
-
-Class*
-generate_rpc_interface_class(const interface_type* iface)
-{
-    // the proxy class
-    InterfaceType* interfaceType = static_cast<InterfaceType*>(
-        NAMES.Find(iface->package, iface->name.data));
-    RpcProxyClass* proxy = new RpcProxyClass(iface, interfaceType);
-
-    // the listener class
-    ListenerClass* listener = new ListenerClass(iface);
-
-    // the presenter class
-    EventListenerClass* presenter = new EventListenerClass(iface, listener->type);
-
-    // the service base class
-    EndpointBaseClass* base = new EndpointBaseClass(iface);
-    proxy->elements.push_back(base);
-
-    // the result dispatcher
-    ResultDispatcherClass* results = new ResultDispatcherClass();
-
-    // all the declared methods of the proxy
-    int index = 0;
-    interface_item_type* item = iface->interface_items;
-    while (item != NULL) {
-        if (item->item_type == METHOD_TYPE) {
-            if (NAMES.Search(((method_type*)item)->type.type.data) == EVENT_FAKE_TYPE) {
-                generate_event_method((method_type*)item, proxy, base, listener, presenter, index);
-            } else {
-                generate_regular_method((method_type*)item, proxy, base, results, index);
-            }
-        }
-        item = item->next;
-        index++;
-    }
-    presenter->DoneWithMethods();
-    base->DoneWithMethods();
-
-    // only add this if there are methods with results / out parameters
-    if (results->needed) {
-        proxy->elements.push_back(results);
-    }
-    if (listener->needed) {
-        proxy->elements.push_back(listener);
-        proxy->elements.push_back(presenter);
-        generate_listener_methods(proxy, presenter->type, listener->type);
-    }
-
-    return proxy;
-}
diff --git a/tools/aidl/main.cpp b/tools/aidl/main.cpp
new file mode 100644
index 0000000..7cc2198
--- /dev/null
+++ b/tools/aidl/main.cpp
@@ -0,0 +1,23 @@
+#include "aidl.h"
+#include "options.h"
+
+#include <stdio.h>
+
+int
+main(int argc, const char **argv)
+{
+    Options options;
+    int result = parse_options(argc, argv, &options);
+    if (result) {
+        return result;
+    }
+
+    switch (options.task) {
+        case COMPILE_AIDL:
+            return compile_aidl(options);
+        case PREPROCESS_AIDL:
+            return preprocess_aidl(options);
+    }
+    fprintf(stderr, "aidl: internal error\n");
+    return 1;
+}
diff --git a/tools/aidl/options.cpp b/tools/aidl/options.cpp
index 7b2daeb..52b0972 100644
--- a/tools/aidl/options.cpp
+++ b/tools/aidl/options.cpp
@@ -48,10 +48,6 @@
         return 0;
     }
 
-    options->task = COMPILE_AIDL;
-    options->failOnParcelable = false;
-    options->autoDepFile = false;
-
     // OPTIONS
     while (i < argc) {
         const char* s = argv[i];
diff --git a/tools/aidl/options.h b/tools/aidl/options.h
index 387e37d..4e95e11 100644
--- a/tools/aidl/options.h
+++ b/tools/aidl/options.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_H
-#define DEVICE_TOOLS_AIDL_H
+#ifndef AIDL_OPTIONS_H_
+#define AIDL_OPTIONS_H_
 
 #include <string.h>
 #include <string>
@@ -15,15 +15,15 @@
 // This struct is the parsed version of the command line options
 struct Options
 {
-    int task;
-    bool failOnParcelable;
+    int task{COMPILE_AIDL};
+    bool failOnParcelable{false};
     vector<string> importPaths;
     vector<string> preprocessedFiles;
     string inputFileName;
     string outputFileName;
     string outputBaseFolder;
     string depFileName;
-    bool autoDepFile;
+    bool autoDepFile{false};
 
     vector<string> filesToPreprocess;
 };
@@ -33,4 +33,4 @@
 // It also prints the usage statement on failure.
 int parse_options(int argc, const char* const* argv, Options *options);
 
-#endif // DEVICE_TOOLS_AIDL_H
+#endif // AIDL_OPTIONS_H_
diff --git a/tools/aidl/options_test.cpp b/tools/aidl/options_test.cpp
deleted file mode 100644
index bd106ce..0000000
--- a/tools/aidl/options_test.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-#include <iostream>
-#include "options.h"
-
-const bool VERBOSE = false;
-
-using namespace std;
-
-struct Answer {
-    const char* argv[8];
-    int result;
-    const char* systemSearchPath[8];
-    const char* localSearchPath[8];
-    const char* inputFileName;
-    language_t nativeLanguage;
-    const char* outputH;
-    const char* outputCPP;
-    const char* outputJava;
-};
-
-bool
-match_arrays(const char* const*expected, const vector<string> &got)
-{
-    int count = 0;
-    while (expected[count] != NULL) {
-        count++;
-    }
-    if (got.size() != count) {
-        return false;
-    }
-    for (int i=0; i<count; i++) {
-        if (got[i] != expected[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-void
-print_array(const char* prefix, const char* const*expected)
-{
-    while (*expected) {
-        cout << prefix << *expected << endl;
-        expected++;
-    }
-}
-
-void
-print_array(const char* prefix, const vector<string> &got)
-{
-    size_t count = got.size();
-    for (size_t i=0; i<count; i++) {
-        cout << prefix << got[i] << endl;
-    }
-}
-
-static int
-test(const Answer& answer)
-{
-    int argc = 0;
-    while (answer.argv[argc]) {
-        argc++;
-    }
-
-    int err = 0;
-
-    Options options;
-    int result = parse_options(argc, answer.argv, &options);
-
-    // result
-    if (((bool)result) != ((bool)answer.result)) {
-        cout << "mismatch: result: got " << result << " expected " <<
-            answer.result << endl;
-        err = 1;
-    }
-
-    if (result != 0) {
-        // if it failed, everything is invalid
-        return err;
-    }
-
-    // systemSearchPath
-    if (!match_arrays(answer.systemSearchPath, options.systemSearchPath)) {
-        cout << "mismatch: systemSearchPath: got" << endl;
-        print_array("        ", options.systemSearchPath);
-        cout << "    expected" << endl;
-        print_array("        ", answer.systemSearchPath);
-        err = 1;
-    }
-
-    // localSearchPath
-    if (!match_arrays(answer.localSearchPath, options.localSearchPath)) {
-        cout << "mismatch: localSearchPath: got" << endl;
-        print_array("        ", options.localSearchPath);
-        cout << "    expected" << endl;
-        print_array("        ", answer.localSearchPath);
-        err = 1;
-    }
-
-    // inputFileName
-    if (answer.inputFileName != options.inputFileName) {
-        cout << "mismatch: inputFileName: got " << options.inputFileName
-            << " expected " << answer.inputFileName << endl;
-        err = 1;
-    }
-
-    // nativeLanguage
-    if (answer.nativeLanguage != options.nativeLanguage) {
-        cout << "mismatch: nativeLanguage: got " << options.nativeLanguage
-            << " expected " << answer.nativeLanguage << endl;
-        err = 1;
-    }
-
-    // outputH
-    if (answer.outputH != options.outputH) {
-        cout << "mismatch: outputH: got " << options.outputH
-            << " expected " << answer.outputH << endl;
-        err = 1;
-    }
-
-    // outputCPP
-    if (answer.outputCPP != options.outputCPP) {
-        cout << "mismatch: outputCPP: got " << options.outputCPP
-            << " expected " << answer.outputCPP << endl;
-        err = 1;
-    }
-
-    // outputJava
-    if (answer.outputJava != options.outputJava) {
-        cout << "mismatch: outputJava: got " << options.outputJava
-            << " expected " << answer.outputJava << endl;
-        err = 1;
-    }
-
-    return err;
-}
-
-const Answer g_tests[] = {
-
-    {
-        /* argv */              { "test", "-i/moof", "-I/blah", "-Ibleh", "-imoo", "inputFileName.aidl_cpp", NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { "/blah", "bleh", NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { "/moof", "moo", NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "outputH",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "outputCPP",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", NULL, NULL, NULL, NULL },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        "outputJava"
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-ocpp", "outputCPP", "-ojava", "outputJava" },
-        /* result */            0,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "inputFileName.aidl_cpp",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "outputH",
-        /* outputCPP */         "outputCPP",
-        /* outputJava */        "outputJava"
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-oh", "outputH", "-oh", "outputH1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ocpp", "outputCPP", "-ocpp", "outputCPP1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-    {
-        /* argv */              { "test", "inputFileName.aidl_cpp", "-ojava", "outputJava", "-ojava", "outputJava1", NULL, NULL },
-        /* result */            1,
-        /* systemSearchPath */  { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* localSearchPath */   { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL },
-        /* inputFileName */     "",
-        /* nativeLanguage */    CPP,
-        /* outputH */           "",
-        /* outputCPP */         "",
-        /* outputJava */        ""
-    },
-
-};
-
-int
-main(int argc, const char** argv)
-{
-    const int count = sizeof(g_tests)/sizeof(g_tests[0]);
-    int matches[count];
-
-    int result = 0;
-    for (int i=0; i<count; i++) {
-        if (VERBOSE) {
-            cout << endl;
-            cout << "---------------------------------------------" << endl;
-            const char* const* p = g_tests[i].argv;
-            while (*p) {
-                cout << " " << *p;
-                p++;
-            }
-            cout << endl;
-            cout << "---------------------------------------------" << endl;
-        }
-        matches[i] = test(g_tests[i]);
-        if (VERBOSE) {
-            if (0 == matches[i]) {
-                cout << "passed" << endl;
-            } else {
-                cout << "failed" << endl;
-            }
-            result |= matches[i];
-        }
-    }
-
-    cout << endl;
-    cout << "=============================================" << endl;
-    cout << "options_test summary" << endl;
-    cout << "=============================================" << endl;
-
-    if (!result) {
-        cout << "passed" << endl;
-    } else {
-        cout << "failed the following tests:" << endl;
-        for (int i=0; i<count; i++) {
-            if (matches[i]) {
-                cout << "   ";
-                const char* const* p = g_tests[i].argv;
-                while (*p) {
-                    cout << " " << *p;
-                    p++;
-                }
-                cout << endl;
-            }
-        }
-    }
-
-    return result;
-}
-
diff --git a/tools/aidl/options_unittest.cpp b/tools/aidl/options_unittest.cpp
new file mode 100644
index 0000000..fec7f87
--- /dev/null
+++ b/tools/aidl/options_unittest.cpp
@@ -0,0 +1,54 @@
+/*
+ * 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 <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "options.h"
+
+using std::vector;
+using std::string;
+
+const char kPreprocessCommandOutputFile[] = "output_file_name";
+const char kPreprocessCommandInput1[] = "input1";
+const char kPreprocessCommandInput2[] = "input2";
+const char kPreprocessCommandInput3[] = "input3";
+const char* kPreprocessCommand[] = {
+    "aidl", "--preprocess",
+    kPreprocessCommandOutputFile,
+    kPreprocessCommandInput1,
+    kPreprocessCommandInput2,
+    kPreprocessCommandInput3,
+};
+
+TEST(OptionsTests, ParsesPreprocess) {
+  Options options;
+  const int argc = sizeof(kPreprocessCommand) / sizeof(*kPreprocessCommand);
+  EXPECT_EQ(parse_options(argc, kPreprocessCommand, &options), 0);
+  EXPECT_EQ(options.task, PREPROCESS_AIDL);
+  EXPECT_EQ(options.failOnParcelable, false);
+  EXPECT_EQ(options.importPaths.size(), 0u);
+  EXPECT_EQ(options.preprocessedFiles.size(), 0u);
+  EXPECT_EQ(options.inputFileName, string{""});
+  EXPECT_EQ(options.outputFileName, string{kPreprocessCommandOutputFile});
+  EXPECT_EQ(options.autoDepFile, false);
+  const vector<string> expected_input{kPreprocessCommandInput1,
+                                      kPreprocessCommandInput2,
+                                      kPreprocessCommandInput3};
+  EXPECT_EQ(options.filesToPreprocess, expected_input);
+}
diff --git a/tools/aidl/os.h b/tools/aidl/os.h
index 79d2c35..752ed47 100644
--- a/tools/aidl/os.h
+++ b/tools/aidl/os.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
-#define _FRAMEWORKS_BASE_TOOLS_AIDL_OS_SEP_H_
+#ifndef AIDL_OS_H_
+#define AIDL_OS_H_
 
 #if defined(_WIN32)
 #define OS_PATH_SEPARATOR '\\'
@@ -23,4 +23,4 @@
 #define OS_PATH_SEPARATOR '/'
 #endif
 
-#endif
+#endif  // AIDL_OS_H_
diff --git a/tools/aidl/search_path.h b/tools/aidl/search_path.h
index 2bf94b1..4fec257 100644
--- a/tools/aidl/search_path.h
+++ b/tools/aidl/search_path.h
@@ -1,5 +1,5 @@
-#ifndef DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-#define DEVICE_TOOLS_AIDL_SEARCH_PATH_H
+#ifndef AIDL_SEARCH_PATH_H_
+#define AIDL_SEARCH_PATH_H_
 
 #include <stdio.h>
 
@@ -19,5 +19,4 @@
 void set_import_paths(const vector<string>& importPaths);
 #endif
 
-#endif // DEVICE_TOOLS_AIDL_SEARCH_PATH_H
-
+#endif // AIDL_SEARCH_PATH_H_
diff --git a/tools/aidl/test_main.cpp b/tools/aidl/test_main.cpp
new file mode 100644
index 0000000..4d820af
--- /dev/null
+++ b/tools/aidl/test_main.cpp
@@ -0,0 +1,6 @@
+#include <gtest/gtest.h>
+
+int main(int argc, char **argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/tools/aidl/tests/end_to_end_tests.cpp b/tools/aidl/tests/end_to_end_tests.cpp
new file mode 100644
index 0000000..54ca603
--- /dev/null
+++ b/tools/aidl/tests/end_to_end_tests.cpp
@@ -0,0 +1,165 @@
+/*
+ * 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 <memory>
+#include <string>
+#include <vector>
+
+#include <base/logging.h>
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <gtest/gtest.h>
+
+#include "aidl.h"
+#include "options.h"
+#include "tests/test_data.h"
+
+using base::FilePath;
+using std::string;
+using std::unique_ptr;
+using std::vector;
+
+using namespace aidl::test_data;
+
+namespace {
+
+const char kDiffTemplate[] = "diff %s %s";
+const char kStubInterfaceTemplate[] = "package %s;\ninterface %s { }";
+const char kStubParcelableTemplate[] = "package %s;\nparcelable %s;";
+
+FilePath GetPathForPackageClass(const char* package_class,
+                                const char* extension) {
+  string rel_path{package_class};
+  for (char& c : rel_path) {
+    if (c == '.') {
+      c = FilePath::kSeparators[0];
+    }
+  }
+  rel_path += extension;
+  return FilePath(rel_path);
+}
+
+void SplitPackageClass(const string& package_class,
+                       FilePath* rel_path,
+                       string* package,
+                       string* class_name) {
+  *package = string{package_class, 0, package_class.rfind('.')};
+  *class_name = string{package_class, package_class.rfind('.') + 1};
+  *rel_path = GetPathForPackageClass(package_class.c_str(), ".aidl");
+}
+
+}  // namespace
+
+class EndToEndTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_TRUE(base::CreateNewTempDirectory(
+        string{"end_to_end_testsyyyy"}, &tmpDir_));
+    inputDir_ = tmpDir_.Append("input");
+    outputDir_ = tmpDir_.Append("output");
+    ASSERT_TRUE(base::CreateDirectory(inputDir_));
+    ASSERT_TRUE(base::CreateDirectory(outputDir_));
+  }
+
+  virtual void TearDown() {
+    ASSERT_TRUE(DeleteFile(tmpDir_, true))
+        << "Failed to remove temp directory: " << tmpDir_.value();
+  }
+
+  FilePath CreateInputFile(const FilePath& relative_path,
+                           const char contents[],
+                           int size) {
+    const FilePath created_file = inputDir_.Append(relative_path);
+    EXPECT_TRUE(base::CreateDirectory(created_file.DirName()));
+    EXPECT_TRUE(base::WriteFile(created_file, contents, size));
+    return created_file;
+  }
+
+  void CreateStubAidlFile(const string& package_class,
+                          const char* file_template) {
+    string package, class_name;
+    FilePath rel_path;
+    SplitPackageClass(package_class, &rel_path, &package, &class_name);
+    const size_t buf_len =
+        strlen(file_template) + package.length() + class_name.length() + 1;
+    unique_ptr<char[]> contents(new char[buf_len]);
+    const int written = snprintf(contents.get(), buf_len, file_template,
+                                 package.c_str(), class_name.c_str());
+    EXPECT_GT(written, 0);
+    CreateInputFile(rel_path, contents.get(), written);
+  }
+
+  void WriteStubAidls(const char** parcelables, const char** interfaces) {
+    while (*parcelables) {
+      CreateStubAidlFile(string{*parcelables}, kStubParcelableTemplate);
+      ++parcelables;
+    }
+    while (*interfaces) {
+      CreateStubAidlFile(string{*interfaces}, kStubInterfaceTemplate);
+      ++interfaces;
+    }
+  }
+
+  void CheckFileContents(const FilePath& rel_path,
+                         const string& expected_content) {
+    string actual_contents;
+    FilePath actual_path = outputDir_.Append(rel_path);
+    if (!ReadFileToString(actual_path, &actual_contents)) {
+      FAIL() << "Failed to read expected output file: " << rel_path.value();
+    }
+    // Generated .java files mention the "original" file as part of their
+    // comment header.  Thus we look for expected_content being a substring.
+    if (actual_contents.find(expected_content) == string::npos) {
+      // When the match fails, display a diff of what's wrong.  This greatly
+      // aids in debugging.
+      FilePath expected_path;
+      EXPECT_TRUE(CreateTemporaryFileInDir(tmpDir_, &expected_path));
+      base::WriteFile(expected_path, expected_content.c_str(),
+                      expected_content.length());
+      const size_t buf_len =
+          strlen(kDiffTemplate) + actual_path.value().length() +
+          expected_path.value().length() + 1;
+      unique_ptr<char[]> diff_cmd(new char[buf_len]);
+      EXPECT_GT(snprintf(diff_cmd.get(), buf_len, kDiffTemplate,
+                         expected_path.value().c_str(),
+                         actual_path.value().c_str()), 0);
+      system(diff_cmd.get());
+      FAIL() << "Actual contents of " << rel_path.value()
+             << " did not match expected content";
+    }
+  }
+
+  FilePath tmpDir_;
+  FilePath inputDir_;
+  FilePath outputDir_;
+};
+
+TEST_F(EndToEndTest, IExampleInterface) {
+  Options options;
+  options.failOnParcelable = true;
+  options.importPaths.push_back(inputDir_.value());
+  options.inputFileName =
+      CreateInputFile(GetPathForPackageClass(kIExampleInterfaceClass, ".aidl"),
+                      kIExampleInterfaceContents,
+                      strlen(kIExampleInterfaceContents)).value();
+  options.autoDepFile = true;
+  options.outputBaseFolder = outputDir_.value();
+  WriteStubAidls(kIExampleInterfaceParcelables, kIExampleInterfaceInterfaces);
+  EXPECT_EQ(compile_aidl(options), 0);
+  CheckFileContents(GetPathForPackageClass(kIExampleInterfaceClass, ".java"),
+                    kIExampleInterfaceJava);
+  // We'd like to check the depends file, but it mentions unique file paths.
+}
diff --git a/tools/aidl/tests/example_interface_test_data.cpp b/tools/aidl/tests/example_interface_test_data.cpp
new file mode 100644
index 0000000..b17a800
--- /dev/null
+++ b/tools/aidl/tests/example_interface_test_data.cpp
@@ -0,0 +1,404 @@
+/*
+ * 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 "tests/test_data.h"
+
+namespace aidl {
+namespace test_data {
+
+const char kIExampleInterfaceClass[] = "android.test.IExampleInterface";
+
+const char* kIExampleInterfaceParcelables[] = {
+  "android.foo.ExampleParcelable",
+  "android.test.ExampleParcelable2",
+  nullptr,
+};
+
+const char* kIExampleInterfaceInterfaces[] = {
+  "android.bar.IAuxInterface",
+  "android.test.IAuxInterface2",
+  nullptr,
+};
+
+const char kIExampleInterfaceContents[] = R"(
+package android.test;
+
+import android.foo.ExampleParcelable;
+import android.test.ExampleParcelable2;
+import android.bar.IAuxInterface;
+import android.test.IAuxInterface2;
+
+interface IExampleInterface {
+    boolean isEnabled();
+    int getState();
+    String getAddress();
+
+    ExampleParcelable[] getParcelables();
+
+    boolean setScanMode(int mode, int duration);
+
+    void registerBinder(IAuxInterface foo);
+    IExampleInterface getRecursiveBinder();
+
+    int takesAnInterface(in IAuxInterface2 arg);
+    int takesAParcelable(in ExampleParcelable2 arg);
+}
+)";
+
+const char kIExampleInterfaceDeps[] =
+R"(/tmp/.org.chromium.Chromium.Cdq7YZ/output/android/test/IExampleInterface.java: \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl \
+  /tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl 
+
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IExampleInterface.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/foo/ExampleParcelable.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/ExampleParcelable2.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/bar/IAuxInterface.aidl :
+/tmp/.org.chromium.Chromium.Cdq7YZ/input/android/test/IAuxInterface2.aidl :)";
+
+const char kIExampleInterfaceJava[] =
+R"(package android.test;
+public interface IExampleInterface extends android.os.IInterface
+{
+/** Local-side IPC implementation stub class. */
+public static abstract class Stub extends android.os.Binder implements android.test.IExampleInterface
+{
+private static final java.lang.String DESCRIPTOR = "android.test.IExampleInterface";
+/** Construct the stub at attach it to the interface. */
+public Stub()
+{
+this.attachInterface(this, DESCRIPTOR);
+}
+/**
+ * Cast an IBinder object into an android.test.IExampleInterface interface,
+ * generating a proxy if needed.
+ */
+public static android.test.IExampleInterface asInterface(android.os.IBinder obj)
+{
+if ((obj==null)) {
+return null;
+}
+android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
+if (((iin!=null)&&(iin instanceof android.test.IExampleInterface))) {
+return ((android.test.IExampleInterface)iin);
+}
+return new android.test.IExampleInterface.Stub.Proxy(obj);
+}
+@Override public android.os.IBinder asBinder()
+{
+return this;
+}
+@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
+{
+switch (code)
+{
+case INTERFACE_TRANSACTION:
+{
+reply.writeString(DESCRIPTOR);
+return true;
+}
+case TRANSACTION_isEnabled:
+{
+data.enforceInterface(DESCRIPTOR);
+boolean _result = this.isEnabled();
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_getState:
+{
+data.enforceInterface(DESCRIPTOR);
+int _result = this.getState();
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_getAddress:
+{
+data.enforceInterface(DESCRIPTOR);
+java.lang.String _result = this.getAddress();
+reply.writeNoException();
+reply.writeString(_result);
+return true;
+}
+case TRANSACTION_getParcelables:
+{
+data.enforceInterface(DESCRIPTOR);
+android.foo.ExampleParcelable[] _result = this.getParcelables();
+reply.writeNoException();
+reply.writeTypedArray(_result, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+return true;
+}
+case TRANSACTION_setScanMode:
+{
+data.enforceInterface(DESCRIPTOR);
+int _arg0;
+_arg0 = data.readInt();
+int _arg1;
+_arg1 = data.readInt();
+boolean _result = this.setScanMode(_arg0, _arg1);
+reply.writeNoException();
+reply.writeInt(((_result)?(1):(0)));
+return true;
+}
+case TRANSACTION_registerBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.bar.IAuxInterface _arg0;
+_arg0 = android.bar.IAuxInterface.Stub.asInterface(data.readStrongBinder());
+this.registerBinder(_arg0);
+reply.writeNoException();
+return true;
+}
+case TRANSACTION_getRecursiveBinder:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IExampleInterface _result = this.getRecursiveBinder();
+reply.writeNoException();
+reply.writeStrongBinder((((_result!=null))?(_result.asBinder()):(null)));
+return true;
+}
+case TRANSACTION_takesAnInterface:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.IAuxInterface2 _arg0;
+_arg0 = android.test.IAuxInterface2.Stub.asInterface(data.readStrongBinder());
+int _result = this.takesAnInterface(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+case TRANSACTION_takesAParcelable:
+{
+data.enforceInterface(DESCRIPTOR);
+android.test.ExampleParcelable2 _arg0;
+if ((0!=data.readInt())) {
+_arg0 = android.test.ExampleParcelable2.CREATOR.createFromParcel(data);
+}
+else {
+_arg0 = null;
+}
+int _result = this.takesAParcelable(_arg0);
+reply.writeNoException();
+reply.writeInt(_result);
+return true;
+}
+}
+return super.onTransact(code, data, reply, flags);
+}
+private static class Proxy implements android.test.IExampleInterface
+{
+private android.os.IBinder mRemote;
+Proxy(android.os.IBinder remote)
+{
+mRemote = remote;
+}
+@Override public android.os.IBinder asBinder()
+{
+return mRemote;
+}
+public java.lang.String getInterfaceDescriptor()
+{
+return DESCRIPTOR;
+}
+@Override public boolean isEnabled() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_isEnabled, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int getState() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getState, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public java.lang.String getAddress() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+java.lang.String _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getAddress, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readString();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.foo.ExampleParcelable[] _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getParcelables, _data, _reply, 0);
+_reply.readException();
+_result = _reply.createTypedArray(android.foo.ExampleParcelable.CREATOR);
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public boolean setScanMode(int mode, int duration) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+boolean _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeInt(mode);
+_data.writeInt(duration);
+mRemote.transact(Stub.TRANSACTION_setScanMode, _data, _reply, 0);
+_reply.readException();
+_result = (0!=_reply.readInt());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((foo!=null))?(foo.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_registerBinder, _data, _reply, 0);
+_reply.readException();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+}
+@Override public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+android.test.IExampleInterface _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+mRemote.transact(Stub.TRANSACTION_getRecursiveBinder, _data, _reply, 0);
+_reply.readException();
+_result = android.test.IExampleInterface.Stub.asInterface(_reply.readStrongBinder());
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+_data.writeStrongBinder((((arg!=null))?(arg.asBinder()):(null)));
+mRemote.transact(Stub.TRANSACTION_takesAnInterface, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+@Override public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException
+{
+android.os.Parcel _data = android.os.Parcel.obtain();
+android.os.Parcel _reply = android.os.Parcel.obtain();
+int _result;
+try {
+_data.writeInterfaceToken(DESCRIPTOR);
+if ((arg!=null)) {
+_data.writeInt(1);
+arg.writeToParcel(_data, 0);
+}
+else {
+_data.writeInt(0);
+}
+mRemote.transact(Stub.TRANSACTION_takesAParcelable, _data, _reply, 0);
+_reply.readException();
+_result = _reply.readInt();
+}
+finally {
+_reply.recycle();
+_data.recycle();
+}
+return _result;
+}
+}
+static final int TRANSACTION_isEnabled = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
+static final int TRANSACTION_getState = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
+static final int TRANSACTION_getAddress = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
+static final int TRANSACTION_getParcelables = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
+static final int TRANSACTION_setScanMode = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
+static final int TRANSACTION_registerBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 5);
+static final int TRANSACTION_getRecursiveBinder = (android.os.IBinder.FIRST_CALL_TRANSACTION + 6);
+static final int TRANSACTION_takesAnInterface = (android.os.IBinder.FIRST_CALL_TRANSACTION + 7);
+static final int TRANSACTION_takesAParcelable = (android.os.IBinder.FIRST_CALL_TRANSACTION + 8);
+}
+public boolean isEnabled() throws android.os.RemoteException;
+public int getState() throws android.os.RemoteException;
+public java.lang.String getAddress() throws android.os.RemoteException;
+public android.foo.ExampleParcelable[] getParcelables() throws android.os.RemoteException;
+public boolean setScanMode(int mode, int duration) throws android.os.RemoteException;
+public void registerBinder(android.bar.IAuxInterface foo) throws android.os.RemoteException;
+public android.test.IExampleInterface getRecursiveBinder() throws android.os.RemoteException;
+public int takesAnInterface(android.test.IAuxInterface2 arg) throws android.os.RemoteException;
+public int takesAParcelable(android.test.ExampleParcelable2 arg) throws android.os.RemoteException;
+})";
+
+}  // namespace test_data
+}  // namespace aidl
diff --git a/tools/aidl/tests/test_data.h b/tools/aidl/tests/test_data.h
new file mode 100644
index 0000000..cd8887f
--- /dev/null
+++ b/tools/aidl/tests/test_data.h
@@ -0,0 +1,33 @@
+/*
+ * 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 AIDL_TESTS_TEST_DATA_H_
+#define AIDL_TESTS_TEST_DATA_H_
+
+namespace aidl {
+namespace test_data {
+
+extern const char kIExampleInterfaceClass[];
+extern const char kIExampleInterfaceContents[];
+extern const char* kIExampleInterfaceParcelables[];
+extern const char* kIExampleInterfaceInterfaces[];
+
+extern const char kIExampleInterfaceDeps[];
+extern const char kIExampleInterfaceJava[];
+
+}  // namespace test_data
+}  // namespace aidl
+#endif // AIDL_TESTS_TEST_DATA_H_
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 1e33e3a..f1726eb 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -36,6 +36,7 @@
 
 import android.annotation.NonNull;
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.util.AttributeSet;
 
 import java.io.File;
@@ -54,6 +55,9 @@
     private ResourceReference mResourceReference;
     private Map<View, String> mOpenDrawerLayouts;
 
+    // Keep in sync with the same value in LayoutInflater.
+    private static final int[] ATTRS_THEME = new int[] {com.android.internal.R.attr.theme };
+
     /**
      * List of class prefixes which are tried first by default.
      * <p/>
@@ -135,11 +139,23 @@
 
     @Override
     public View createViewFromTag(View parent, String name, Context context, AttributeSet attrs,
-            boolean ignoreThemeAttrs) {
+            boolean ignoreThemeAttr) {
         View view;
         try {
-            view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttrs);
+            view = super.createViewFromTag(parent, name, context, attrs, ignoreThemeAttr);
         } catch (InflateException e) {
+            // Creation of ContextThemeWrapper code is same as in the super method.
+            // Apply a theme wrapper, if allowed and one is specified.
+            if (!ignoreThemeAttr) {
+                final TypedArray ta = context.obtainStyledAttributes(attrs, ATTRS_THEME);
+                final int themeResId = ta.getResourceId(0, 0);
+                if (themeResId != 0) {
+                    context = new ContextThemeWrapper(context, themeResId);
+                }
+                ta.recycle();
+            }
+            final Object lastContext = mConstructorArgs[0];
+            mConstructorArgs[0] = context;
             // try to load the class from using the custom view loader
             try {
                 view = loadCustomView(name, attrs);
@@ -153,6 +169,8 @@
                     exception.initCause(e);
                 }
                 throw exception;
+            } finally {
+                mConstructorArgs[0] = lastContext;
             }
         }
 
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index a8fd91c..ed8b56e 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -74,11 +74,10 @@
     // ---- unused implementation of IWindowManager ----
 
     @Override
-    public Configuration addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
+    public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
             boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
-            Rect arg11) throws RemoteException {
+            Rect arg11, Configuration arg12) throws RemoteException {
         // TODO Auto-generated method stub
-        return Configuration.EMPTY;
     }
 
     @Override
@@ -315,9 +314,9 @@
     }
 
     @Override
-    public Configuration setAppTask(IBinder arg0, int arg1, Rect arg2) throws RemoteException {
+    public void setAppTask(IBinder arg0, int arg1, Rect arg2, Configuration arg3)
+            throws RemoteException {
         // TODO Auto-generated method stub
-        return Configuration.EMPTY;
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java b/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java
deleted file mode 100644
index 8e41e51..0000000
--- a/tools/layoutlib/bridge/src/android/widget/SimpleMonthView_Delegate.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.icu.text.SimpleDateFormat;
-import android.text.format.DateFormat;
-
-import java.util.Calendar;
-import java.util.Locale;
-
-/**
- * Delegate that provides implementation for some methods in {@link SimpleMonthView}.
- * <p/>
- * Through the layoutlib_create tool, selected methods of SimpleMonthView have been replaced by
- * calls to methods of the same name in this delegate class.
- * <p/>
- * The main purpose of this class is to use {@link android.icu.text.SimpleDateFormat} instead of
- * {@link java.text.SimpleDateFormat}.
- */
-public class SimpleMonthView_Delegate {
-
-    private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
-    private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
-
-    // Maintain a cache of the last view used, so that the formatters can be reused.
-    @Nullable private static SimpleMonthView sLastView;
-    @Nullable private static SimpleMonthView_Delegate sLastDelegate;
-
-    private SimpleDateFormat mTitleFormatter;
-    private SimpleDateFormat mDayOfWeekFormatter;
-
-    private Locale locale;
-
-    @LayoutlibDelegate
-    /*package*/ static CharSequence getTitle(SimpleMonthView view) {
-        if (view.mTitle == null) {
-            SimpleMonthView_Delegate delegate = getDelegate(view);
-            if (delegate.mTitleFormatter == null) {
-                delegate.mTitleFormatter = new SimpleDateFormat(DateFormat.getBestDateTimePattern(
-                        getLocale(delegate, view), DEFAULT_TITLE_FORMAT));
-            }
-            view.mTitle = delegate.mTitleFormatter.format(view.mCalendar.getTime());
-        }
-        return view.mTitle;
-    }
-
-    @LayoutlibDelegate
-    /*package*/ static String getDayOfWeekLabel(SimpleMonthView view, int dayOfWeek) {
-        view.mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
-        SimpleMonthView_Delegate delegate = getDelegate(view);
-        if (delegate.mDayOfWeekFormatter == null) {
-            delegate.mDayOfWeekFormatter =
-                    new SimpleDateFormat(DAY_OF_WEEK_FORMAT, getLocale(delegate, view));
-        }
-        return delegate.mDayOfWeekFormatter.format(view.mDayOfWeekLabelCalendar.getTime());
-    }
-
-    private static Locale getLocale(SimpleMonthView_Delegate delegate, SimpleMonthView view) {
-        if (delegate.locale == null) {
-            delegate.locale = view.getContext().getResources().getConfiguration().locale;
-        }
-        return delegate.locale;
-    }
-
-    @NonNull
-    private static SimpleMonthView_Delegate getDelegate(SimpleMonthView view) {
-        if (view == sLastView) {
-            assert sLastDelegate != null;
-            return sLastDelegate;
-        } else {
-            sLastView = view;
-            sLastDelegate = new SimpleMonthView_Delegate();
-            return sLastDelegate;
-        }
-    }
-
-    public static void clearCache() {
-        sLastView = null;
-        sLastDelegate = null;
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 1f3802e..689e359 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -36,8 +36,8 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
-import android.annotation.Nullable;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -139,8 +139,9 @@
     private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
     private int mDynamicIdGenerator = 0x02030000; // Base id for R.style in custom namespace
 
-    // cache for TypedArray generated from IStyleResourceValue object
-    private Map<int[], Map<Integer, BridgeTypedArray>> mTypedArrayCache;
+    // cache for TypedArray generated from StyleResourceValue object
+    private Map<int[], Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>
+            mTypedArrayCache;
     private BridgeInflater mBridgeInflater;
 
     private BridgeContentResolver mContentResolver;
@@ -621,31 +622,38 @@
             }
         }
 
+        // The map is from
+        // attrs (int[]) -> context's current themes (List<StyleRV>) -> resid (int) -> typed array.
         if (mTypedArrayCache == null) {
-            mTypedArrayCache = new HashMap<int[], Map<Integer,BridgeTypedArray>>();
-
-            Map<Integer, BridgeTypedArray> map = new HashMap<Integer, BridgeTypedArray>();
-            mTypedArrayCache.put(attrs, map);
-
-            BridgeTypedArray ta = createStyleBasedTypedArray(style, attrs);
-            map.put(resid, ta);
-
-            return ta;
+            mTypedArrayCache = new IdentityHashMap<int[],
+                    Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>>();
         }
 
         // get the 2nd map
-        Map<Integer, BridgeTypedArray> map = mTypedArrayCache.get(attrs);
-        if (map == null) {
-            map = new HashMap<Integer, BridgeTypedArray>();
-            mTypedArrayCache.put(attrs, map);
+        Map<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>> map2 =
+                mTypedArrayCache.get(attrs);
+        if (map2 == null) {
+            map2 = new HashMap<List<StyleResourceValue>, Map<Integer, BridgeTypedArray>>();
+            mTypedArrayCache.put(attrs, map2);
         }
 
-        // get the array from the 2nd map
-        BridgeTypedArray ta = map.get(resid);
+        // get the 3rd map
+        List<StyleResourceValue> currentThemes = mRenderResources.getAllThemes();
+        Map<Integer, BridgeTypedArray> map3 = map2.get(currentThemes);
+        if (map3 == null) {
+            map3 = new HashMap<Integer, BridgeTypedArray>();
+            // Create a copy of the list before adding it to the map. This allows reusing the
+            // existing list.
+            currentThemes = new ArrayList<StyleResourceValue>(currentThemes);
+            map2.put(currentThemes, map3);
+        }
+
+        // get the array from the 3rd map
+        BridgeTypedArray ta = map3.get(resid);
 
         if (ta == null) {
             ta = createStyleBasedTypedArray(style, attrs);
-            map.put(resid, ta);
+            map3.put(resid, ta);
         }
 
         return ta;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 92b39e3..a833ebe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -36,7 +36,6 @@
 import android.view.ViewConfiguration_Accessor;
 import android.view.inputmethod.InputMethodManager;
 import android.view.inputmethod.InputMethodManager_Accessor;
-import android.widget.SimpleMonthView_Delegate;
 
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
@@ -278,7 +277,6 @@
             mContext.getRenderResources().setLogger(null);
         }
         ParserFactory.setParserFactory(null);
-        SimpleMonthView_Delegate.clearCache();
     }
 
     public static BridgeContext getCurrentContext() {
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 8f0ad01..f6c2626 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -77,8 +77,6 @@
     /** Methods to inject. FQCN of class in which method should be injected => runnable that does
      * the injection. */
     private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
-    /** A map { FQCN => set { field names } } which should be promoted to public visibility */
-    private final Map<String, Set<String>> mPromotedFields;
 
     /**
      * Creates a new generator that can generate the output JAR with the stubbed classes.
@@ -111,8 +109,20 @@
 
         // Create the map/set of methods to change to delegates
         mDelegateMethods = new HashMap<String, Set<String>>();
-        addToMap(createInfo.getDelegateMethods(), mDelegateMethods);
-
+        for (String signature : createInfo.getDelegateMethods()) {
+            int pos = signature.indexOf('#');
+            if (pos <= 0 || pos >= signature.length() - 1) {
+                continue;
+            }
+            String className = binaryToInternalClassName(signature.substring(0, pos));
+            String methodName = signature.substring(pos + 1);
+            Set<String> methods = mDelegateMethods.get(className);
+            if (methods == null) {
+                methods = new HashSet<String>();
+                mDelegateMethods.put(className, methods);
+            }
+            methods.add(methodName);
+        }
         for (String className : createInfo.getDelegateClassNatives()) {
             className = binaryToInternalClassName(className);
             Set<String> methods = mDelegateMethods.get(className);
@@ -177,34 +187,10 @@
             returnTypes.add(binaryToInternalClassName(className));
         }
 
-        mPromotedFields = new HashMap<String, Set<String>>();
-        addToMap(createInfo.getPromotedFields(), mPromotedFields);
-
         mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
     }
 
     /**
-     * For each value in the array, split the value on '#' and add the parts to the map as key
-     * and value.
-     */
-    private void addToMap(String[] entries, Map<String, Set<String>> map) {
-        for (String entry : entries) {
-            int pos = entry.indexOf('#');
-            if (pos <= 0 || pos >= entry.length() - 1) {
-                return;
-            }
-            String className = binaryToInternalClassName(entry.substring(0, pos));
-            String methodOrFieldName = entry.substring(pos + 1);
-            Set<String> set = map.get(className);
-            if (set == null) {
-                set = new HashSet<String>();
-                map.put(className, set);
-            }
-            set.add(methodOrFieldName);
-        }
-    }
-
-    /**
      * Returns the list of classes that have not been renamed yet.
      * <p/>
      * The names are "internal class names" rather than FQCN, i.e. they use "/" instead "."
@@ -394,10 +380,6 @@
             }
         }
 
-        Set<String> promoteFields = mPromotedFields.get(className);
-        if (promoteFields != null && !promoteFields.isEmpty()) {
-            cv = new PromoteFieldClassAdapter(cv, promoteFields);
-        }
         cr.accept(cv, 0);
         return cw.toByteArray();
     }
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 484240f..499bea4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -120,11 +120,6 @@
     }
 
     @Override
-    public String[] getPromotedFields() {
-        return PROMOTED_FIELDS;
-    }
-
-    @Override
     public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
         return INJECTED_METHODS;
     }
@@ -190,8 +185,6 @@
         "android.view.RenderNode#nSetElevation",
         "android.view.RenderNode#nGetElevation",
         "android.view.ViewGroup#drawChild",
-        "android.widget.SimpleMonthView#getTitle",
-        "android.widget.SimpleMonthView#getDayOfWeekLabel",
         "android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
         "com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
         "com.android.internal.util.XmlUtils#convertValueToInt",
@@ -296,12 +289,6 @@
             "org.kxml2.io.KXmlParser"
         };
 
-    private final static String[] PROMOTED_FIELDS = new String[] {
-        "android.widget.SimpleMonthView#mTitle",
-        "android.widget.SimpleMonthView#mCalendar",
-        "android.widget.SimpleMonthView#mDayOfWeekLabelCalendar"
-    };
-
     /**
      * List of classes for which the methods returning them should be deleted.
      * The array contains a list of null terminated section starting with the name of the class
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 6c62423..54b1fe6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -78,13 +78,6 @@
     Set<String> getExcludedClasses();
 
     /**
-     * Returns a list of fields which should be promoted to public visibility. The array values
-     * are in the form of the binary FQCN of the class containing the field and the field name
-     * separated by a '#'.
-     */
-    String[] getPromotedFields();
-
-    /**
      * Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
      * called to inject methods into a class.
      * Can be empty but must not be null.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
deleted file mode 100644
index e4b70da..0000000
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tools.layoutlib.create;
-
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-
-import java.util.Set;
-
-import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
-import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ASM4;
-
-/**
- * Promotes given fields to public visibility.
- */
-public class PromoteFieldClassAdapter extends ClassVisitor {
-
-    private final Set<String> mFieldNames;
-    private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED);
-
-    public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) {
-        super(ASM4, cv);
-        mFieldNames = fieldNames;
-    }
-
-    @Override
-    public FieldVisitor visitField(int access, String name, String desc, String signature,
-            Object value) {
-        if (mFieldNames.contains(name)) {
-            if ((access & ACC_PUBLIC) == 0) {
-                access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC;
-            }
-        }
-        return super.visitField(access, name, desc, signature, value);
-    }
-}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 8a2235b..2c21470 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -138,11 +138,6 @@
             }
 
             @Override
-            public String[] getPromotedFields() {
-                return new String[0];
-            }
-
-            @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
                 return new HashMap<String, InjectMethodRunnable>(0);
             }
@@ -218,11 +213,6 @@
             }
 
             @Override
-            public String[] getPromotedFields() {
-                return new String[0];
-            }
-
-            @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
                 return new HashMap<String, InjectMethodRunnable>(0);
             }
@@ -306,11 +296,6 @@
             }
 
             @Override
-            public String[] getPromotedFields() {
-                return new String[0];
-            }
-
-            @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
                 return new HashMap<String, InjectMethodRunnable>(0);
             }
@@ -389,11 +374,6 @@
             }
 
             @Override
-            public String[] getPromotedFields() {
-                return new String[0];
-            }
-
-            @Override
             public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
                 HashMap<String, InjectMethodRunnable> map =
                         new HashMap<String, InjectMethodRunnable>(1);
diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk
index d9ddf08..239bed5 100644
--- a/tools/split-select/Android.mk
+++ b/tools/split-select/Android.mk
@@ -43,7 +43,6 @@
     external/zlib \
     frameworks/base/tools
 
-hostLdLibs :=
 hostStaticLibs := \
     libaapt \
     libandroidfw \
@@ -57,17 +56,13 @@
 
 cFlags := -Wall -Werror
 
-ifeq ($(HOST_OS),linux)
-    hostLdLibs += -lrt -ldl -lpthread
-endif
+hostLdLibs_linux := -lrt -ldl -lpthread
 
 # Statically link libz for MinGW (Win SDK under Linux),
 # and dynamically link for all others.
-ifneq ($(strip $(USE_MINGW)),)
-    hostStaticLibs += libz
-else
-    hostLdLibs += -lz
-endif
+hostStaticLibs_windows := libz
+hostLdLibs_darwin := -lz
+hostLdLibs_linux += -lz
 
 
 # ==========================================================
@@ -75,11 +70,12 @@
 # ==========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := libsplit-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := $(sources)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_CFLAGS := $(cFlags) -D_DARWIN_UNLIMITED_STREAMS
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
@@ -93,10 +89,12 @@
 
 LOCAL_SRC_FILES := $(testSources)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
 
 include $(BUILD_HOST_NATIVE_TEST)
 
@@ -105,13 +103,16 @@
 # ==========================================================
 include $(CLEAR_VARS)
 LOCAL_MODULE := split-select
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 LOCAL_SRC_FILES := $(main)
 
-LOCAL_C_INCLUDES += $(cIncludes)
-LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs)
-LOCAL_LDLIBS += $(hostLdLibs)
-LOCAL_CFLAGS += $(cFlags)
+LOCAL_C_INCLUDES := $(cIncludes)
+LOCAL_STATIC_LIBRARIES := libsplit-select $(hostStaticLibs)
+LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
+LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
+LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
+LOCAL_CFLAGS := $(cFlags)
 
 include $(BUILD_HOST_EXECUTABLE)