Merge "QS prototype work"
diff --git a/Android.mk b/Android.mk
index 769a555..40da134 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,7 @@
 	core/java/android/app/IWallpaperManager.aidl \
 	core/java/android/app/IWallpaperManagerCallback.aidl \
 	core/java/android/app/admin/IDevicePolicyManager.aidl \
+	core/java/android/app/trust/IStrongAuthTracker.aidl \
 	core/java/android/app/trust/ITrustManager.aidl \
 	core/java/android/app/trust/ITrustListener.aidl \
 	core/java/android/app/backup/IBackupManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index acc9c4b..e9c5727 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -21,6 +21,7 @@
     field public static final deprecated java.lang.String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final java.lang.String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final java.lang.String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
+    field public static final java.lang.String BIND_CONDITION_PROVIDER_SERVICE = "android.permission.BIND_CONDITION_PROVIDER_SERVICE";
     field public static final java.lang.String BIND_DEVICE_ADMIN = "android.permission.BIND_DEVICE_ADMIN";
     field public static final java.lang.String BIND_DREAM_SERVICE = "android.permission.BIND_DREAM_SERVICE";
     field public static final java.lang.String BIND_INCALL_SERVICE = "android.permission.BIND_INCALL_SERVICE";
@@ -240,8 +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 activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+    field public static final int activityWidth = 16844018; // 0x10104f2
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -8881,6 +8884,7 @@
     field public int configChanges;
     field public int documentLaunchMode;
     field public int flags;
+    field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
     field public int launchMode;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
@@ -8894,6 +8898,15 @@
     field public int uiOptions;
   }
 
+  public static final class ActivityInfo.InitialLayout {
+    ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+    field public final int gravity;
+    field public final int height;
+    field public final float heightFraction;
+    field public final int width;
+    field public final float widthFraction;
+  }
+
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     ctor public ApplicationInfo();
     ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -18102,7 +18115,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);
   }
 
@@ -18136,7 +18149,7 @@
     method public final int getThumbPixWidth();
   }
 
-  public class MtpObjectInfo.Builder {
+  public static class MtpObjectInfo.Builder {
     ctor public MtpObjectInfo.Builder();
     ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
     method public android.mtp.MtpObjectInfo build();
@@ -28731,6 +28744,49 @@
 
 package android.service.notification {
 
+  public class Condition implements android.os.Parcelable {
+    ctor public Condition(android.net.Uri, java.lang.String, java.lang.String, java.lang.String, int, int, int);
+    method public android.service.notification.Condition copy();
+    method public int describeContents();
+    method public static boolean isValidId(android.net.Uri, java.lang.String);
+    method public static android.net.Uri.Builder newId(android.content.Context);
+    method public static java.lang.String relevanceToString(int);
+    method public static java.lang.String stateToString(int);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.service.notification.Condition> CREATOR;
+    field public static final int FLAG_RELEVANT_ALWAYS = 2; // 0x2
+    field public static final int FLAG_RELEVANT_NOW = 1; // 0x1
+    field public static final java.lang.String SCHEME = "condition";
+    field public static final int STATE_ERROR = 3; // 0x3
+    field public static final int STATE_FALSE = 0; // 0x0
+    field public static final int STATE_TRUE = 1; // 0x1
+    field public static final int STATE_UNKNOWN = 2; // 0x2
+    field public final int flags;
+    field public final int icon;
+    field public final android.net.Uri id;
+    field public final java.lang.String line1;
+    field public final java.lang.String line2;
+    field public final int state;
+    field public final java.lang.String summary;
+  }
+
+  public abstract class ConditionProviderService extends android.app.Service {
+    ctor public ConditionProviderService();
+    method public final void notifyCondition(android.service.notification.Condition);
+    method public final void notifyConditions(android.service.notification.Condition...);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract void onConnected();
+    method public abstract void onRequestConditions(int);
+    method public abstract void onSubscribe(android.net.Uri);
+    method public abstract void onUnsubscribe(android.net.Uri);
+    field public static final java.lang.String EXTRA_CONDITION_ID = "android.content.automatic.conditionId";
+    field public static final java.lang.String EXTRA_RULE_NAME = "android.content.automatic.ruleName";
+    field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final java.lang.String META_DATA_DEFAULT_CONDITION_ID = "android.service.zen.automatic.defaultConditionId";
+    field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
+    field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -30623,6 +30679,7 @@
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+    field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
@@ -32512,7 +32569,7 @@
     method public static int getLayoutDirectionFromLocale(java.util.Locale);
     method public static int getOffsetAfter(java.lang.CharSequence, int);
     method public static int getOffsetBefore(java.lang.CharSequence, int);
-    method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+    method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
     method public static int getTrimmedLength(java.lang.CharSequence);
     method public static java.lang.String htmlEncode(java.lang.String);
     method public static int indexOf(java.lang.CharSequence, char);
diff --git a/api/system-current.txt b/api/system-current.txt
index 955fb07..e234970 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -333,8 +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 activityOpenEnterAnimation = 16842936; // 0x10100b8
     field public static final int activityOpenExitAnimation = 16842937; // 0x10100b9
+    field public static final int activityWidth = 16844018; // 0x10104f2
     field public static final int addPrintersActivity = 16843750; // 0x10103e6
     field public static final int addStatesFromChildren = 16842992; // 0x10100f0
     field public static final int adjustViewBounds = 16843038; // 0x101011e
@@ -9139,6 +9141,7 @@
     field public int configChanges;
     field public int documentLaunchMode;
     field public int flags;
+    field public android.content.pm.ActivityInfo.InitialLayout initialLayout;
     field public int launchMode;
     field public int maxRecents;
     field public java.lang.String parentActivityName;
@@ -9152,6 +9155,15 @@
     field public int uiOptions;
   }
 
+  public static final class ActivityInfo.InitialLayout {
+    ctor public ActivityInfo.InitialLayout(int, float, int, float, int);
+    field public final int gravity;
+    field public final int height;
+    field public final float heightFraction;
+    field public final int width;
+    field public final float widthFraction;
+  }
+
   public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
     ctor public ApplicationInfo();
     ctor public ApplicationInfo(android.content.pm.ApplicationInfo);
@@ -19615,7 +19627,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);
   }
 
@@ -19649,7 +19661,7 @@
     method public final int getThumbPixWidth();
   }
 
-  public class MtpObjectInfo.Builder {
+  public static class MtpObjectInfo.Builder {
     ctor public MtpObjectInfo.Builder();
     ctor public MtpObjectInfo.Builder(android.mtp.MtpObjectInfo);
     method public android.mtp.MtpObjectInfo build();
@@ -30856,6 +30868,11 @@
     method public abstract void onRequestConditions(int);
     method public abstract void onSubscribe(android.net.Uri);
     method public abstract void onUnsubscribe(android.net.Uri);
+    field public static final java.lang.String EXTRA_CONDITION_ID = "android.content.automatic.conditionId";
+    field public static final java.lang.String EXTRA_RULE_NAME = "android.content.automatic.ruleName";
+    field public static final java.lang.String META_DATA_CONFIGURATION_ACTIVITY = "android.service.zen.automatic.configurationActivity";
+    field public static final java.lang.String META_DATA_DEFAULT_CONDITION_ID = "android.service.zen.automatic.defaultConditionId";
+    field public static final java.lang.String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
@@ -32893,6 +32910,7 @@
     field public static final java.lang.String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool";
     field public static final java.lang.String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool";
     field public static final java.lang.String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool";
+    field public static final java.lang.String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
     field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
@@ -34845,7 +34863,7 @@
     method public static int getLayoutDirectionFromLocale(java.util.Locale);
     method public static int getOffsetAfter(java.lang.CharSequence, int);
     method public static int getOffsetBefore(java.lang.CharSequence, int);
-    method public static java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
+    method public static deprecated java.lang.CharSequence getReverse(java.lang.CharSequence, int, int);
     method public static int getTrimmedLength(java.lang.CharSequence);
     method public static java.lang.String htmlEncode(java.lang.String);
     method public static int indexOf(java.lang.CharSequence, char);
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 2ee586f..7c8842c 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -27,6 +27,8 @@
 
 LOCAL_MODULE:= bootanimation
 
+LOCAL_INIT_RC := bootanim.rc
+
 ifdef TARGET_32_BIT_SURFACEFLINGER
 LOCAL_32_BIT_ONLY := true
 endif
diff --git a/cmds/bootanimation/bootanim.rc b/cmds/bootanimation/bootanim.rc
new file mode 100644
index 0000000..ee0d0b8
--- /dev/null
+++ b/cmds/bootanimation/bootanim.rc
@@ -0,0 +1,6 @@
+service bootanim /system/bin/bootanimation
+    class core
+    user graphics
+    group graphics audio
+    disabled
+    oneshot
diff --git a/cmds/dpm/src/com/android/commands/dpm/Dpm.java b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
index f9b3419..471fa3b 100644
--- a/cmds/dpm/src/com/android/commands/dpm/Dpm.java
+++ b/cmds/dpm/src/com/android/commands/dpm/Dpm.java
@@ -107,7 +107,7 @@
 
     private void runSetDeviceOwner() throws RemoteException {
         ComponentName component = parseComponentName(nextArgRequired());
-        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, UserHandle.USER_OWNER);
+        mDevicePolicyManager.setActiveAdmin(component, true /*refreshing*/, UserHandle.USER_SYSTEM);
 
         String packageName = component.getPackageName();
         try {
@@ -117,7 +117,7 @@
             }
         } catch (Exception e) {
             // Need to remove the admin that we just added.
-            mDevicePolicyManager.removeActiveAdmin(component, UserHandle.USER_OWNER);
+            mDevicePolicyManager.removeActiveAdmin(component, UserHandle.USER_SYSTEM);
             throw e;
         }
         System.out.println("Success: Device owner set to package " + packageName);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index f66a4c7..3f0a444 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -51,6 +51,7 @@
 import android.content.res.AssetManager;
 import android.content.res.Resources;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IUserManager;
@@ -987,6 +988,7 @@
             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: return "ask";
             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: return "always";
             case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: return "never";
+            case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK : return "always ask";
         }
         return "Unknown link state: " + state;
     }
@@ -1094,6 +1096,7 @@
             }
         }
 
+        userId = translateUserId(userId, "runInstall");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
             installFlags |= PackageManager.INSTALL_ALL_USERS;
@@ -1164,6 +1167,16 @@
         }
     }
 
+    /**
+     * @param userId The user id to be translated.
+     * @param logContext Optional human readable text to provide some context in error log.
+     * @return Translated concrete user id.  This will include USER_ALL.
+     */
+    private int translateUserId(int userId, String logContext) {
+        return ActivityManager.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
+                userId, true, true, logContext, "pm command");
+    }
+
     private int runInstallCreate() throws RemoteException {
         int userId = UserHandle.USER_ALL;
         String installerPackageName = null;
@@ -1220,6 +1233,7 @@
             }
         }
 
+        userId = translateUserId(userId, "runInstallCreate");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
             params.installFlags |= PackageManager.INSTALL_ALL_USERS;
@@ -1551,6 +1565,7 @@
             return 1;
         }
 
+        userId = translateUserId(userId, "runUninstall");
         if (userId == UserHandle.USER_ALL) {
             userId = UserHandle.USER_SYSTEM;
             flags |= PackageManager.DELETE_ALL_USERS;
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
index c551482..cb39e37 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/ShellUiAutomatorBridge.java
@@ -61,7 +61,7 @@
             IBinder token = new Binder();
             try {
                 ContentProviderHolder holder = activityManager.getContentProviderExternal(
-                        providerName, UserHandle.USER_OWNER, token);
+                        providerName, UserHandle.USER_SYSTEM, token);
                 if (holder == null) {
                     throw new IllegalStateException("Could not find provider: " + providerName);
                 }
diff --git a/core/java/android/animation/AnimationHandler.java b/core/java/android/animation/AnimationHandler.java
new file mode 100644
index 0000000..7778c35
--- /dev/null
+++ b/core/java/android/animation/AnimationHandler.java
@@ -0,0 +1,316 @@
+/*
+ * 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.animation;
+
+import android.os.SystemClock;
+import android.util.ArrayMap;
+import android.view.Choreographer;
+
+import java.util.ArrayList;
+
+/**
+ * This custom, static handler handles the timing pulse that is shared by all active
+ * ValueAnimators. This approach ensures that the setting of animation values will happen on the
+ * same thread that animations start on, and that all animations will share the same times for
+ * calculating their values, which makes synchronizing animations possible.
+ *
+ * The handler uses the Choreographer by default for doing periodic callbacks. A custom
+ * AnimationFrameCallbackProvider can be set on the handler to provide timing pulse that
+ * may be independent of UI frame update. This could be useful in testing.
+ *
+ * @hide
+ */
+public class AnimationHandler {
+    /**
+     * Internal per-thread collections used to avoid set collisions as animations start and end
+     * while being processed.
+     * @hide
+     */
+    private final ArrayMap<AnimationFrameCallback, Long> mDelayedCallbackStartTime =
+            new ArrayMap<>();
+    private final ArrayList<AnimationFrameCallback> mAnimationCallbacks =
+            new ArrayList<>();
+    private final ArrayList<AnimationFrameCallback> mCommitCallbacks =
+            new ArrayList<>();
+    private AnimationFrameCallbackProvider mProvider;
+
+    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
+        @Override
+        public void doFrame(long frameTimeNanos) {
+            doAnimationFrame(getProvider().getFrameTime());
+            if (mAnimationCallbacks.size() > 0) {
+                getProvider().postFrameCallback(this);
+            }
+        }
+    };
+
+    public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();
+    private boolean mListDirty = false;
+
+    public static AnimationHandler getInstance() {
+        if (sAnimatorHandler.get() == null) {
+            sAnimatorHandler.set(new AnimationHandler());
+        }
+        return sAnimatorHandler.get();
+    }
+
+    /**
+     * By default, the Choreographer is used to provide timing for frame callbacks. A custom
+     * provider can be used here to provide different timing pulse.
+     */
+    public void setProvider(AnimationFrameCallbackProvider provider) {
+        if (provider == null) {
+            mProvider = new MyFrameCallbackProvider();
+        } else {
+            mProvider = provider;
+        }
+    }
+
+    private AnimationFrameCallbackProvider getProvider() {
+        if (mProvider == null) {
+            mProvider = new MyFrameCallbackProvider();
+        }
+        return mProvider;
+    }
+
+    /**
+     * Register to get a callback on the next frame after the delay.
+     */
+    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
+        if (mAnimationCallbacks.size() == 0) {
+            getProvider().postFrameCallback(mFrameCallback);
+        }
+        if (!mAnimationCallbacks.contains(callback)) {
+            mAnimationCallbacks.add(callback);
+        }
+
+        if (delay > 0) {
+            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
+        }
+    }
+
+    /**
+     * Register to get a one shot callback for frame commit timing. Frame commit timing is the
+     * time *after* traversals are done, as opposed to the animation frame timing, which is
+     * before any traversals. This timing can be used to adjust the start time of an animation
+     * when expensive traversals create big delta between the animation frame timing and the time
+     * that animation is first shown on screen.
+     *
+     * Note this should only be called when the animation has already registered to receive
+     * animation frame callbacks. This callback will be guaranteed to happen *after* the next
+     * animation frame callback.
+     */
+    public void addOneShotCommitCallback(final AnimationFrameCallback callback) {
+        if (!mCommitCallbacks.contains(callback)) {
+            mCommitCallbacks.add(callback);
+        }
+    }
+
+    /**
+     * Removes the given callback from the list, so it will no longer be called for frame related
+     * timing.
+     */
+    public void removeCallback(AnimationFrameCallback callback) {
+        mCommitCallbacks.remove(callback);
+        mDelayedCallbackStartTime.remove(callback);
+        int id = mAnimationCallbacks.indexOf(callback);
+        if (id >= 0) {
+            mAnimationCallbacks.set(id, null);
+            mListDirty = true;
+        }
+    }
+
+    private void doAnimationFrame(long frameTime) {
+        int size = mAnimationCallbacks.size();
+        long currentTime = SystemClock.uptimeMillis();
+        for (int i = 0; i < size; i++) {
+            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
+            if (callback == null) {
+                continue;
+            }
+            if (isCallbackDue(callback, currentTime)) {
+                callback.doAnimationFrame(frameTime);
+                if (mCommitCallbacks.contains(callback)) {
+                    getProvider().postCommitCallback(new Runnable() {
+                        @Override
+                        public void run() {
+                            commitAnimationFrame(callback, getProvider().getFrameTime());
+                        }
+                    });
+                }
+            }
+        }
+        cleanUpList();
+    }
+
+    private void commitAnimationFrame(AnimationFrameCallback callback, long frameTime) {
+        if (!mDelayedCallbackStartTime.containsKey(callback) &&
+                mCommitCallbacks.contains(callback)) {
+            callback.commitAnimationFrame(frameTime);
+            mCommitCallbacks.remove(callback);
+        }
+    }
+
+    /**
+     * Remove the callbacks from mDelayedCallbackStartTime once they have passed the initial delay
+     * so that they can start getting frame callbacks.
+     *
+     * @return true if they have passed the initial delay or have no delay, false otherwise.
+     */
+    private boolean isCallbackDue(AnimationFrameCallback callback, long currentTime) {
+        Long startTime = mDelayedCallbackStartTime.get(callback);
+        if (startTime == null) {
+            return true;
+        }
+        if (startTime < currentTime) {
+            mDelayedCallbackStartTime.remove(callback);
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return the number of callbacks that have registered for frame callbacks.
+     */
+    public static int getAnimationCount() {
+        AnimationHandler handler = sAnimatorHandler.get();
+        if (handler == null) {
+            return 0;
+        }
+        return handler.getCallbackSize();
+    }
+
+    public static void setFrameDelay(long delay) {
+        getInstance().getProvider().setFrameDelay(delay);
+    }
+
+    public static long getFrameDelay() {
+        return getInstance().getProvider().getFrameDelay();
+    }
+
+    void autoCancelBasedOn(ObjectAnimator objectAnimator) {
+        for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
+            AnimationFrameCallback cb = mAnimationCallbacks.get(i);
+            if (cb == null) {
+                continue;
+            }
+            if (objectAnimator.shouldAutoCancel(cb)) {
+                ((Animator) mAnimationCallbacks.get(i)).cancel();
+            }
+        }
+    }
+
+    private void cleanUpList() {
+        if (mListDirty) {
+            for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
+                if (mAnimationCallbacks.get(i) == null) {
+                    mAnimationCallbacks.remove(i);
+                }
+            }
+            mListDirty = false;
+        }
+    }
+
+    private int getCallbackSize() {
+        int count = 0;
+        int size = mAnimationCallbacks.size();
+        for (int i = size - 1; i >= 0; i--) {
+            if (mAnimationCallbacks.get(i) != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    /**
+     * Default provider of timing pulse that uses Choreographer for frame callbacks.
+     */
+    private class MyFrameCallbackProvider implements AnimationFrameCallbackProvider {
+
+        final Choreographer mChoreographer = Choreographer.getInstance();
+
+        @Override
+        public void postFrameCallback(Choreographer.FrameCallback callback) {
+            mChoreographer.postFrameCallback(callback);
+        }
+
+        @Override
+        public void postCommitCallback(Runnable runnable) {
+            mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, runnable, null);
+        }
+
+        @Override
+        public long getFrameTime() {
+            return mChoreographer.getFrameTime();
+        }
+
+        @Override
+        public long getFrameDelay() {
+            return Choreographer.getFrameDelay();
+        }
+
+        @Override
+        public void setFrameDelay(long delay) {
+            Choreographer.setFrameDelay(delay);
+        }
+    }
+
+    /**
+     * Callbacks that receives notifications for animation timing and frame commit timing.
+     */
+    interface AnimationFrameCallback {
+        /**
+         * Run animation based on the frame time.
+         * @param frameTime The frame start time, in the {@link SystemClock#uptimeMillis()} time
+         *                  base.
+         */
+        void doAnimationFrame(long frameTime);
+
+        /**
+         * This notifies the callback of frame commit time. Frame commit time is the time after
+         * traversals happen, as opposed to the normal animation frame time that is before
+         * traversals. This is used to compensate expensive traversals that happen as the
+         * animation starts. When traversals take a long time to complete, the rendering of the
+         * initial frame will be delayed (by a long time). But since the startTime of the
+         * animation is set before the traversal, by the time of next frame, a lot of time would
+         * have passed since startTime was set, the animation will consequently skip a few frames
+         * to respect the new frameTime. By having the commit time, we can adjust the start time to
+         * when the first frame was drawn (after any expensive traversals) so that no frames
+         * will be skipped.
+         *
+         * @param frameTime The frame time after traversals happen, if any, in the
+         *                  {@link SystemClock#uptimeMillis()} time base.
+         */
+        void commitAnimationFrame(long frameTime);
+    }
+
+    /**
+     * The intention for having this interface is to increase the testability of ValueAnimator.
+     * Specifically, we can have a custom implementation of the interface below and provide
+     * timing pulse without using Choreographer. That way we could use any arbitrary interval for
+     * our timing pulse in the tests.
+     *
+     * @hide
+     */
+    public interface AnimationFrameCallbackProvider {
+        void postFrameCallback(Choreographer.FrameCallback callback);
+        void postCommitCallback(Runnable runnable);
+        long getFrameTime();
+        long getFrameDelay();
+        void setFrameDelay(long delay);
+    }
+}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index f9333739..26c886e 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -25,6 +25,7 @@
 import android.util.Property;
 
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 
 /**
  * This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
@@ -809,37 +810,7 @@
 
     @Override
     public void start() {
-        // See if any of the current active/pending animators need to be canceled
-        AnimationHandler handler = sAnimationHandler.get();
-        if (handler != null) {
-            int numAnims = handler.mAnimations.size();
-            for (int i = numAnims - 1; i >= 0; i--) {
-                if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
-                    ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
-                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
-                        anim.cancel();
-                    }
-                }
-            }
-            numAnims = handler.mPendingAnimations.size();
-            for (int i = numAnims - 1; i >= 0; i--) {
-                if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
-                    ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
-                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
-                        anim.cancel();
-                    }
-                }
-            }
-            numAnims = handler.mDelayedAnims.size();
-            for (int i = numAnims - 1; i >= 0; i--) {
-                if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
-                    ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
-                    if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
-                        anim.cancel();
-                    }
-                }
-            }
-        }
+        AnimationHandler.getInstance().autoCancelBasedOn(this);
         if (DBG) {
             Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
             for (int i = 0; i < mValues.length; ++i) {
@@ -852,6 +823,20 @@
         super.start();
     }
 
+    boolean shouldAutoCancel(AnimationHandler.AnimationFrameCallback anim) {
+        if (anim == null) {
+            return false;
+        }
+
+        if (anim instanceof ObjectAnimator) {
+            ObjectAnimator objAnim = (ObjectAnimator) anim;
+            if (objAnim.mAutoCancel && hasSameTargetAndProperties(objAnim)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * This function is called immediately before processing the first animation
      * frame of an animation. If there is a nonzero <code>startDelay</code>, the
diff --git a/core/java/android/animation/TimeAnimator.java b/core/java/android/animation/TimeAnimator.java
index 1ba68df..113a21f 100644
--- a/core/java/android/animation/TimeAnimator.java
+++ b/core/java/android/animation/TimeAnimator.java
@@ -37,7 +37,7 @@
     }
 
     @Override
-    boolean animationFrame(long currentTime) {
+    boolean animateBasedOnTime(long currentTime) {
         if (mListener != null) {
             long totalTime = currentTime - mStartTime;
             long deltaTime = (mPreviousTime < 0) ? 0 : (currentTime - mPreviousTime);
@@ -52,7 +52,7 @@
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = Math.max(mStartTime, currentTime - playTime);
         mStartTimeCommitted = true; // do not allow start time to be compensated for jank
-        animationFrame(currentTime);
+        animateBasedOnTime(currentTime);
     }
 
     /**
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 35a8816..da9a8c8 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -21,7 +21,6 @@
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
 import android.util.Log;
-import android.view.Choreographer;
 import android.view.animation.AccelerateDecelerateInterpolator;
 import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
@@ -64,7 +63,7 @@
  * </div>
  */
 @SuppressWarnings("unchecked")
-public class ValueAnimator extends Animator {
+public class ValueAnimator extends Animator implements AnimationHandler.AnimationFrameCallback {
     private static final String TAG = "ValueAnimator";
     private static final boolean DEBUG = false;
 
@@ -74,14 +73,6 @@
     private static float sDurationScale = 1.0f;
 
     /**
-     * Values used with internal variable mPlayingState to indicate the current state of an
-     * animation.
-     */
-    static final int STOPPED    = 0; // Not yet playing
-    static final int RUNNING    = 1; // Playing normally
-    static final int SEEKED     = 2; // Seeked to some time value
-
-    /**
      * Internal variables
      * NOTE: This object implements the clone() method, making a deep copy of any referenced
      * objects. As other non-trivial fields are added to this class, make sure to add logic
@@ -130,15 +121,6 @@
      */
     private boolean mResumed = false;
 
-
-    // The static sAnimationHandler processes the internal timing loop on which all animations
-    // are based
-    /**
-     * @hide
-     */
-    protected static ThreadLocal<AnimationHandler> sAnimationHandler =
-            new ThreadLocal<AnimationHandler>();
-
     // The time interpolator to be used if none is set on the animation
     private static final TimeInterpolator sDefaultInterpolator =
             new AccelerateDecelerateInterpolator();
@@ -170,25 +152,9 @@
     private float mCurrentFraction = 0f;
 
     /**
-     * Tracks whether a startDelay'd animation has begun playing through the startDelay.
+     * Tracks the time (in milliseconds) when the last frame arrived.
      */
-    private boolean mStartedDelay = false;
-
-    /**
-     * Tracks the time at which the animation began playing through its startDelay. This is
-     * different from the mStartTime variable, which is used to track when the animation became
-     * active (which is when the startDelay expired and the animation was added to the active
-     * animations list).
-     */
-    private long mDelayStartTime;
-
-    /**
-     * Flag that represents the current state of the animation. Used to figure out when to start
-     * an animation (if state == STOPPED). Also used to end an animation that
-     * has been cancel()'d or end()'d since the last animation frame. Possible values are
-     * STOPPED, RUNNING, SEEKED.
-     */
-    int mPlayingState = STOPPED;
+    private long mLastFrameTime = 0;
 
     /**
      * Additional playing state to indicate whether an animator has been start()'d. There is
@@ -219,16 +185,21 @@
      */
     boolean mInitialized = false;
 
+    /**
+     * Flag that tracks whether animation has been requested to end.
+     */
+    private boolean mAnimationEndRequested = false;
+
     //
     // Backing variables
     //
 
     // How long the animation should last in ms
-    private long mDuration = (long)(300 * sDurationScale);
     private long mUnscaledDuration = 300;
+    private long mDuration = (long)(mUnscaledDuration * sDurationScale);
 
     // The amount of time in ms to delay starting the animation after start() is called
-    private long mStartDelay = 0;
+    long mStartDelay = 0;
     private long mUnscaledStartDelay = 0;
 
     // The number of times the animation will repeat. The default is 0, which means the animation
@@ -285,7 +256,6 @@
      */
     public static final int INFINITE = -1;
 
-
     /**
      * @hide
      */
@@ -539,7 +509,6 @@
         }
     }
 
-
     /**
      * Sets the length of the animation. The default duration is 300 milliseconds.
      *
@@ -644,9 +613,8 @@
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = currentTime - seekTime;
         mStartTimeCommitted = true; // do not allow start time to be compensated for jank
-        if (mPlayingState != RUNNING) {
+        if (!mRunning) {
             mSeekFraction = fraction;
-            mPlayingState = SEEKED;
         }
         if (mPlayingBackwards) {
             fraction = 1f - fraction;
@@ -662,168 +630,13 @@
      * @return The current position in time of the animation.
      */
     public long getCurrentPlayTime() {
-        if (!mInitialized || mPlayingState == STOPPED) {
+        if (!mInitialized || !mStarted) {
             return 0;
         }
         return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
     }
 
     /**
-     * This custom, static handler handles the timing pulse that is shared by
-     * all active animations. This approach ensures that the setting of animation
-     * values will happen on the UI thread and that all animations will share
-     * the same times for calculating their values, which makes synchronizing
-     * animations possible.
-     *
-     * The handler uses the Choreographer for executing periodic callbacks.
-     *
-     * @hide
-     */
-    @SuppressWarnings("unchecked")
-    protected static class AnimationHandler {
-        // The per-thread list of all active animations
-        /** @hide */
-        protected final ArrayList<ValueAnimator> mAnimations = new ArrayList<ValueAnimator>();
-
-        // Used in doAnimationFrame() to avoid concurrent modifications of mAnimations
-        private final ArrayList<ValueAnimator> mTmpAnimations = new ArrayList<ValueAnimator>();
-
-        // The per-thread set of animations to be started on the next animation frame
-        /** @hide */
-        protected final ArrayList<ValueAnimator> mPendingAnimations = new ArrayList<ValueAnimator>();
-
-        /**
-         * Internal per-thread collections used to avoid set collisions as animations start and end
-         * while being processed.
-         * @hide
-         */
-        protected final ArrayList<ValueAnimator> mDelayedAnims = new ArrayList<ValueAnimator>();
-        private final ArrayList<ValueAnimator> mEndingAnims = new ArrayList<ValueAnimator>();
-        private final ArrayList<ValueAnimator> mReadyAnims = new ArrayList<ValueAnimator>();
-
-        private final Choreographer mChoreographer;
-        private boolean mAnimationScheduled;
-        private long mLastFrameTime;
-
-        private AnimationHandler() {
-            mChoreographer = Choreographer.getInstance();
-        }
-
-        /**
-         * Start animating on the next frame.
-         */
-        public void start() {
-            scheduleAnimation();
-        }
-
-        void doAnimationFrame(long frameTime) {
-            mLastFrameTime = frameTime;
-
-            // mPendingAnimations holds any animations that have requested to be started
-            // We're going to clear mPendingAnimations, but starting animation may
-            // cause more to be added to the pending list (for example, if one animation
-            // starting triggers another starting). So we loop until mPendingAnimations
-            // is empty.
-            while (mPendingAnimations.size() > 0) {
-                ArrayList<ValueAnimator> pendingCopy =
-                        (ArrayList<ValueAnimator>) mPendingAnimations.clone();
-                mPendingAnimations.clear();
-                int count = pendingCopy.size();
-                for (int i = 0; i < count; ++i) {
-                    ValueAnimator anim = pendingCopy.get(i);
-                    // If the animation has a startDelay, place it on the delayed list
-                    if (anim.mStartDelay == 0) {
-                        anim.startAnimation(this);
-                    } else {
-                        mDelayedAnims.add(anim);
-                    }
-                }
-            }
-
-            // Next, process animations currently sitting on the delayed queue, adding
-            // them to the active animations if they are ready
-            int numDelayedAnims = mDelayedAnims.size();
-            for (int i = 0; i < numDelayedAnims; ++i) {
-                ValueAnimator anim = mDelayedAnims.get(i);
-                if (anim.delayedAnimationFrame(frameTime)) {
-                    mReadyAnims.add(anim);
-                }
-            }
-            int numReadyAnims = mReadyAnims.size();
-            if (numReadyAnims > 0) {
-                for (int i = 0; i < numReadyAnims; ++i) {
-                    ValueAnimator anim = mReadyAnims.get(i);
-                    anim.startAnimation(this);
-                    anim.mRunning = true;
-                    mDelayedAnims.remove(anim);
-                }
-                mReadyAnims.clear();
-            }
-
-            // Now process all active animations. The return value from animationFrame()
-            // tells the handler whether it should now be ended
-            int numAnims = mAnimations.size();
-            for (int i = 0; i < numAnims; ++i) {
-                mTmpAnimations.add(mAnimations.get(i));
-            }
-            for (int i = 0; i < numAnims; ++i) {
-                ValueAnimator anim = mTmpAnimations.get(i);
-                if (mAnimations.contains(anim) && anim.doAnimationFrame(frameTime)) {
-                    mEndingAnims.add(anim);
-                }
-            }
-            mTmpAnimations.clear();
-            if (mEndingAnims.size() > 0) {
-                for (int i = 0; i < mEndingAnims.size(); ++i) {
-                    mEndingAnims.get(i).endAnimation(this);
-                }
-                mEndingAnims.clear();
-            }
-
-            // Schedule final commit for the frame.
-            mChoreographer.postCallback(Choreographer.CALLBACK_COMMIT, mCommit, null);
-
-            // If there are still active or delayed animations, schedule a future call to
-            // onAnimate to process the next frame of the animations.
-            if (!mAnimations.isEmpty() || !mDelayedAnims.isEmpty()) {
-                scheduleAnimation();
-            }
-        }
-
-        void commitAnimationFrame(long frameTime) {
-            final long adjustment = frameTime - mLastFrameTime;
-            final int numAnims = mAnimations.size();
-            for (int i = 0; i < numAnims; ++i) {
-                mAnimations.get(i).commitAnimationFrame(adjustment);
-            }
-        }
-
-        private void scheduleAnimation() {
-            if (!mAnimationScheduled) {
-                mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimate, null);
-                mAnimationScheduled = true;
-            }
-        }
-
-        // Called by the Choreographer.
-        final Runnable mAnimate = new Runnable() {
-            @Override
-            public void run() {
-                mAnimationScheduled = false;
-                doAnimationFrame(mChoreographer.getFrameTime());
-            }
-        };
-
-        // Called by the Choreographer.
-        final Runnable mCommit = new Runnable() {
-            @Override
-            public void run() {
-                commitAnimationFrame(mChoreographer.getFrameTime());
-            }
-        };
-    }
-
-    /**
      * The amount of time, in milliseconds, to delay starting the animation after
      * {@link #start()} is called.
      *
@@ -859,7 +672,7 @@
      * @return the requested time between frames, in milliseconds
      */
     public static long getFrameDelay() {
-        return Choreographer.getFrameDelay();
+        return AnimationHandler.getInstance().getFrameDelay();
     }
 
     /**
@@ -875,7 +688,7 @@
      * @param frameDelay the requested time between frames, in milliseconds
      */
     public static void setFrameDelay(long frameDelay) {
-        Choreographer.setFrameDelay(frameDelay);
+        AnimationHandler.getInstance().setFrameDelay(frameDelay);
     }
 
     /**
@@ -1104,24 +917,13 @@
                 mPlayingBackwards = (mCurrentIteration % 2) != 0;
             }
         }
-        int prevPlayingState = mPlayingState;
-        mPlayingState = STOPPED;
         mStarted = true;
-        mStartedDelay = false;
         mPaused = false;
+        mRunning = false;
+        mAnimationEndRequested = false;
         updateScaledDuration(); // in case the scale factor has changed since creation time
-        AnimationHandler animationHandler = getOrCreateAnimationHandler();
-        animationHandler.mPendingAnimations.add(this);
-        if (mStartDelay == 0) {
-            // This sets the initial value of the animation, prior to actually starting it running
-            if (prevPlayingState != SEEKED) {
-                setCurrentPlayTime(0);
-            }
-            mPlayingState = STOPPED;
-            mRunning = true;
-            notifyStartListeners();
-        }
-        animationHandler.start();
+        AnimationHandler animationHandler = AnimationHandler.getInstance();
+        animationHandler.addAnimationFrameCallback(this, mStartDelay);
     }
 
     @Override
@@ -1131,41 +933,48 @@
 
     @Override
     public void cancel() {
+        if (Looper.myLooper() == null) {
+            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+        }
+
+        // If end has already been requested, through a previous end() or cancel() call, no-op
+        // until animation starts again.
+        if (mAnimationEndRequested) {
+            return;
+        }
+
         // Only cancel if the animation is actually running or has been started and is about
         // to run
-        AnimationHandler handler = getOrCreateAnimationHandler();
-        if (mPlayingState != STOPPED
-                || handler.mPendingAnimations.contains(this)
-                || handler.mDelayedAnims.contains(this)) {
-            // Only notify listeners if the animator has actually started
-            if ((mStarted || mRunning) && mListeners != null) {
-                if (!mRunning) {
-                    // If it's not yet running, then start listeners weren't called. Call them now.
-                    notifyStartListeners();
-                }
-                ArrayList<AnimatorListener> tmpListeners =
-                        (ArrayList<AnimatorListener>) mListeners.clone();
-                for (AnimatorListener listener : tmpListeners) {
-                    listener.onAnimationCancel(this);
-                }
+        // Only notify listeners if the animator has actually started
+        if ((mStarted || mRunning) && mListeners != null) {
+            if (!mRunning) {
+                // If it's not yet running, then start listeners weren't called. Call them now.
+                notifyStartListeners();
             }
-            endAnimation(handler);
+            ArrayList<AnimatorListener> tmpListeners =
+                    (ArrayList<AnimatorListener>) mListeners.clone();
+            for (AnimatorListener listener : tmpListeners) {
+                listener.onAnimationCancel(this);
+            }
         }
+        endAnimation();
+
     }
 
     @Override
     public void end() {
-        AnimationHandler handler = getOrCreateAnimationHandler();
-        if (!handler.mAnimations.contains(this) && !handler.mPendingAnimations.contains(this)) {
+        if (Looper.myLooper() == null) {
+            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
+        }
+        if (!mRunning) {
             // Special case if the animation has not yet started; get it ready for ending
-            mStartedDelay = false;
-            startAnimation(handler);
+            startAnimation();
             mStarted = true;
         } else if (!mInitialized) {
             initAnimation();
         }
         animateValue(mPlayingBackwards ? 0f : 1f);
-        endAnimation(handler);
+        endAnimation();
     }
 
     @Override
@@ -1188,7 +997,7 @@
 
     @Override
     public boolean isRunning() {
-        return (mPlayingState == RUNNING || mRunning);
+        return mRunning;
     }
 
     @Override
@@ -1206,7 +1015,7 @@
     @Override
     public void reverse() {
         mPlayingBackwards = !mPlayingBackwards;
-        if (mPlayingState == RUNNING) {
+        if (mRunning) {
             long currentTime = AnimationUtils.currentAnimationTimeMillis();
             long currentPlayTime = currentTime - mStartTime;
             long timeLeft = mDuration - currentPlayTime;
@@ -1231,13 +1040,15 @@
     /**
      * Called internally to end an animation by removing it from the animations list. Must be
      * called on the UI thread.
-     * @hide
      */
-    protected void endAnimation(AnimationHandler handler) {
-        handler.mAnimations.remove(this);
-        handler.mPendingAnimations.remove(this);
-        handler.mDelayedAnims.remove(this);
-        mPlayingState = STOPPED;
+    private void endAnimation() {
+        if (mAnimationEndRequested) {
+            return;
+        }
+        AnimationHandler handler = AnimationHandler.getInstance();
+        handler.removeCallback(this);
+
+        mAnimationEndRequested = true;
         mPaused = false;
         if ((mStarted || mRunning) && mListeners != null) {
             if (!mRunning) {
@@ -1267,16 +1078,14 @@
      * Called internally to start an animation by adding it to the active animations list. Must be
      * called on the UI thread.
      */
-    private void startAnimation(AnimationHandler handler) {
+    private void startAnimation() {
         if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
             Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                     System.identityHashCode(this));
         }
         initAnimation();
-        handler.mAnimations.add(this);
-        if (mStartDelay > 0 && mListeners != null) {
-            // Listeners were already notified in start() if startDelay is 0; this is
-            // just for delayed animations
+        mRunning = true;
+        if (mListeners != null) {
             notifyStartListeners();
         }
     }
@@ -1288,53 +1097,16 @@
         return "animator";
     }
 
-
-    /**
-     * Internal function called to process an animation frame on an animation that is currently
-     * sleeping through its <code>startDelay</code> phase. The return value indicates whether it
-     * should be woken up and put on the active animations queue.
-     *
-     * @param currentTime The current animation time, used to calculate whether the animation
-     * has exceeded its <code>startDelay</code> and should be started.
-     * @return True if the animation's <code>startDelay</code> has been exceeded and the animation
-     * should be added to the set of active animations.
-     */
-    private boolean delayedAnimationFrame(long currentTime) {
-        if (!mStartedDelay) {
-            mStartedDelay = true;
-            mDelayStartTime = currentTime;
-        }
-        if (mPaused) {
-            if (mPauseTime < 0) {
-                mPauseTime = currentTime;
-            }
-            return false;
-        } else if (mResumed) {
-            mResumed = false;
-            if (mPauseTime > 0) {
-                // Offset by the duration that the animation was paused
-                mDelayStartTime += (currentTime - mPauseTime);
-            }
-        }
-        long deltaTime = currentTime - mDelayStartTime;
-        if (deltaTime > mStartDelay) {
-            // startDelay ended - start the anim and record the mStartTime appropriately
-            mStartTime = mDelayStartTime + mStartDelay;
-            mStartTimeCommitted = true; // do not allow start time to be compensated for jank
-            mPlayingState = RUNNING;
-            return true;
-        }
-        return false;
-    }
-
     /**
      * Applies an adjustment to the animation to compensate for jank between when
      * the animation first ran and when the frame was drawn.
+     * @hide
      */
-    void commitAnimationFrame(long adjustment) {
+    public void commitAnimationFrame(long frameTime) {
         if (!mStartTimeCommitted) {
             mStartTimeCommitted = true;
-            if (mPlayingState == RUNNING && adjustment > 0) {
+            long adjustment = frameTime - mLastFrameTime;
+            if (adjustment > 0) {
                 mStartTime += adjustment;
                 if (DEBUG) {
                     Log.d(TAG, "Adjusted start time by " + adjustment + " ms: " + toString());
@@ -1353,13 +1125,11 @@
      *
      * @param currentTime The current time, as tracked by the static timing handler
      * @return true if the animation's duration, including any repetitions due to
-     * <code>repeatCount</code>, has been exceeded and the animation should be ended.
+     * <code>repeatCount</code> has been exceeded and the animation should be ended.
      */
-    boolean animationFrame(long currentTime) {
+    boolean animateBasedOnTime(long currentTime) {
         boolean done = false;
-        switch (mPlayingState) {
-        case RUNNING:
-        case SEEKED:
+        if (mRunning) {
             float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
             if (mDuration == 0 && mRepeatCount != INFINITE) {
                 // Skip to the end
@@ -1394,9 +1164,7 @@
                 fraction = 1f - fraction;
             }
             animateValue(fraction);
-            break;
         }
-
         return done;
     }
 
@@ -1405,10 +1173,15 @@
      *
      * @param frameTime The frame time.
      * @return true if the animation has ended.
+     * @hide
      */
-    final boolean doAnimationFrame(long frameTime) {
-        if (mPlayingState == STOPPED) {
-            mPlayingState = RUNNING;
+    public final void doAnimationFrame(long frameTime) {
+        mLastFrameTime = frameTime;
+        AnimationHandler handler = AnimationHandler.getInstance();
+        if (!mRunning) {
+            // First frame
+            handler.addOneShotCommitCallback(this);
+            startAnimation();
             if (mSeekFraction < 0) {
                 mStartTime = frameTime;
             } else {
@@ -1422,7 +1195,7 @@
             if (mPauseTime < 0) {
                 mPauseTime = frameTime;
             }
-            return false;
+            return;
         } else if (mResumed) {
             mResumed = false;
             if (mPauseTime > 0) {
@@ -1430,13 +1203,18 @@
                 mStartTime += (frameTime - mPauseTime);
                 mStartTimeCommitted = false; // allow start time to be compensated for jank
             }
+            handler.addOneShotCommitCallback(this);
         }
         // The frame time might be before the start time during the first frame of
         // an animation.  The "current time" must always be on or after the start
         // time to avoid animating frames at negative time intervals.  In practice, this
         // is very rare and only happens when seeking backwards.
         final long currentTime = Math.max(frameTime, mStartTime);
-        return animationFrame(currentTime);
+        boolean finished = animateBasedOnTime(currentTime);
+
+        if (finished) {
+            endAnimation();
+        }
     }
 
     /**
@@ -1488,8 +1266,6 @@
         anim.mReversing = false;
         anim.mCurrentIteration = 0;
         anim.mInitialized = false;
-        anim.mPlayingState = STOPPED;
-        anim.mStartedDelay = false;
         anim.mStarted = false;
         anim.mRunning = false;
         anim.mPaused = false;
@@ -1497,9 +1273,10 @@
         anim.mStartListenersCalled = false;
         anim.mStartTime = 0;
         anim.mStartTimeCommitted = false;
+        anim.mAnimationEndRequested = false;
         anim.mPauseTime = 0;
+        anim.mLastFrameTime = 0;
         anim.mCurrentFraction = 0;
-        anim.mDelayStartTime = 0;
 
         PropertyValuesHolder[] oldValues = mValues;
         if (oldValues != null) {
@@ -1540,32 +1317,7 @@
      * @hide
      */
     public static int getCurrentAnimationsCount() {
-        AnimationHandler handler = sAnimationHandler.get();
-        return handler != null ? handler.mAnimations.size() : 0;
-    }
-
-    /**
-     * Clear all animations on this thread, without canceling or ending them.
-     * This should be used with caution.
-     *
-     * @hide
-     */
-    public static void clearAllAnimations() {
-        AnimationHandler handler = sAnimationHandler.get();
-        if (handler != null) {
-            handler.mAnimations.clear();
-            handler.mPendingAnimations.clear();
-            handler.mDelayedAnims.clear();
-        }
-    }
-
-    private static AnimationHandler getOrCreateAnimationHandler() {
-        AnimationHandler handler = sAnimationHandler.get();
-        if (handler == null) {
-            handler = new AnimationHandler();
-            sAnimationHandler.set(handler);
-        }
-        return handler;
+        return AnimationHandler.getAnimationCount();
     }
 
     @Override
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 07fa52c..a4e1135 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.
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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index fe79629..412e3cd 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1727,7 +1727,8 @@
             String[] libDirs, int displayId, Configuration overrideConfiguration,
             LoadedApk pkgInfo) {
         return mResourcesManager.getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
-                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
+                displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo(),
+                pkgInfo.getClassLoader());
     }
 
     final Handler getHandler() {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 235f294..fca5567 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1838,7 +1838,7 @@
                 resources = mResourcesManager.getTopLevelResources(packageInfo.getResDir(),
                         packageInfo.getSplitResDirs(), packageInfo.getOverlayDirs(),
                         packageInfo.getApplicationInfo().sharedLibraryFiles, displayId,
-                        overrideConfiguration, compatInfo);
+                        overrideConfiguration, compatInfo, packageInfo.getClassLoader());
             }
         }
         mResources = resources;
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 2117597..3187984 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -154,10 +154,12 @@
      * @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,
-            Configuration overrideConfiguration, CompatibilityInfo compatInfo) {
+            Configuration overrideConfiguration, CompatibilityInfo compatInfo,
+            ClassLoader classLoader) {
         final float scale = compatInfo.applicationScale;
         Configuration overrideConfigCopy = (overrideConfiguration != null)
                 ? new Configuration(overrideConfiguration) : null;
@@ -237,7 +239,7 @@
         } else {
             config = getConfiguration();
         }
-        r = new Resources(assets, dm, config, compatInfo);
+        r = new Resources(assets, dm, config, compatInfo, classLoader);
         if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                 + r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
 
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index 7718a36..9ea2ba2 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -401,7 +401,19 @@
                             activeSet.add(canonicalJournalPath);
                             if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
                                 Log.v(TAG_XML_PARSER, "...automatically generated "
-                                        + canonicalJournalPath + ". Ignore if nonexistant.");
+                                        + canonicalJournalPath + ". Ignore if nonexistent.");
+                            }
+                        }
+
+                        // Special case for sharedpref files (not dirs) also add ".xml" suffix file.
+                        if ("sharedpref".equals(domainFromXml) && !canonicalFile.isDirectory() &&
+                            !canonicalFile.getCanonicalPath().endsWith(".xml")) {
+                            final String canonicalXmlPath =
+                                    canonicalFile.getCanonicalPath() + ".xml";
+                            activeSet.add(canonicalXmlPath);
+                            if (Log.isLoggable(TAG_XML_PARSER, Log.VERBOSE)) {
+                                Log.v(TAG_XML_PARSER, "...automatically generated "
+                                        + canonicalXmlPath + ". Ignore if nonexistent.");
                             }
                         }
                 }
diff --git a/core/java/android/app/backup/WallpaperBackupHelper.java b/core/java/android/app/backup/WallpaperBackupHelper.java
index 7a80936..30c11ef 100644
--- a/core/java/android/app/backup/WallpaperBackupHelper.java
+++ b/core/java/android/app/backup/WallpaperBackupHelper.java
@@ -56,11 +56,12 @@
 
     // This path must match what the WallpaperManagerService uses
     // TODO: Will need to change if backing up non-primary user's wallpaper
+    // http://b/22388012
     public static final String WALLPAPER_IMAGE =
-            new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+            new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
                     "wallpaper").getAbsolutePath();
     public static final String WALLPAPER_INFO =
-            new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+            new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
                     "wallpaper_info.xml").getAbsolutePath();
     // Use old keys to keep legacy data compatibility and avoid writing two wallpapers
     public static final String WALLPAPER_IMAGE_KEY =
@@ -71,8 +72,9 @@
     // will be saved to this file from the restore stream, then renamed to the proper
     // location if it's deemed suitable.
     // TODO: Will need to change if backing up non-primary user's wallpaper
+    // http://b/22388012
     private static final String STAGE_FILE =
-            new File(Environment.getUserSystemDirectory(UserHandle.USER_OWNER),
+            new File(Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM),
                     "wallpaper-tmp").getAbsolutePath();
 
     Context mContext;
diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl
new file mode 100644
index 0000000..36c71bf
--- /dev/null
+++ b/core/java/android/app/trust/IStrongAuthTracker.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app.trust;
+
+/**
+ * Private API to be notified about strong auth changes
+ *
+ * {@hide}
+ */
+oneway interface IStrongAuthTracker {
+    void onStrongAuthRequiredChanged(int strongAuthRequired, int userId);
+}
\ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 32951d9..2dea545 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -26,11 +26,9 @@
 interface ITrustManager {
     void reportUnlockAttempt(boolean successful, int userId);
     void reportEnabledTrustAgentsChanged(int userId);
-    void reportRequireCredentialEntry(int userId);
     void registerTrustListener(in ITrustListener trustListener);
     void unregisterTrustListener(in ITrustListener trustListener);
     void reportKeyguardShowingChanged();
     boolean isDeviceLocked(int userId);
     boolean isDeviceSecure(int userId);
-    boolean hasUserAuthenticatedSinceBoot(int userId);
 }
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 8cab565..aff69f0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,13 +16,19 @@
 
 package android.app.trust;
 
+import android.annotation.IntDef;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseIntArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
  * See {@link com.android.server.trust.TrustManagerService}
@@ -73,21 +79,6 @@
     }
 
     /**
-     * Reports that trust is disabled until credentials have been entered for user {@param userId}.
-     *
-     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     *
-     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
-     */
-    public void reportRequireCredentialEntry(int userId) {
-        try {
-            mService.reportRequireCredentialEntry(userId);
-        } catch (RemoteException e) {
-            onError(e);
-        }
-    }
-
-    /**
      * Reports that the visibility of the keyguard has changed.
      *
      * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
@@ -147,23 +138,6 @@
         }
     }
 
-    /**
-     * Checks whether the specified user has been authenticated since the last boot.
-     *
-     * @param userId the user id of the user to check for
-     * @return true if the user has authenticated since boot, false otherwise
-     *
-     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
-     */
-    public boolean hasUserAuthenticatedSinceBoot(int userId) {
-        try {
-            return mService.hasUserAuthenticatedSinceBoot(userId);
-        } catch (RemoteException e) {
-            onError(e);
-            return false;
-        }
-    }
-
     private void onError(Exception e) {
         Log.e(TAG, "Error while calling TrustManagerService", e);
     }
diff --git a/core/java/android/content/RestrictionEntry.java b/core/java/android/content/RestrictionEntry.java
index ab049ec..0473475 100644
--- a/core/java/android/content/RestrictionEntry.java
+++ b/core/java/android/content/RestrictionEntry.java
@@ -456,7 +456,7 @@
         if (o == this) return true;
         if (!(o instanceof RestrictionEntry)) return false;
         final RestrictionEntry other = (RestrictionEntry) o;
-        if (mType != other.mType || mKey.equals(other.mKey)) {
+        if (mType != other.mType || !mKey.equals(other.mKey)) {
             return false;
         }
         if (mCurrentValues == null && other.mCurrentValues == null
diff --git a/core/java/android/content/RestrictionsManager.java b/core/java/android/content/RestrictionsManager.java
index 1fac06e..a7744e7 100644
--- a/core/java/android/content/RestrictionsManager.java
+++ b/core/java/android/content/RestrictionsManager.java
@@ -677,7 +677,8 @@
      * <table>
      *     <tr><th>RestrictionEntry</th><th>Bundle</th></tr>
      *     <tr><td>{@link RestrictionEntry#TYPE_BOOLEAN}</td><td>{@link Bundle#putBoolean}</td></tr>
-     *     <tr><td>{@link RestrictionEntry#TYPE_CHOICE}, {@link RestrictionEntry#TYPE_CHOICE}</td>
+     *     <tr><td>{@link RestrictionEntry#TYPE_CHOICE},
+     *     {@link RestrictionEntry#TYPE_MULTI_SELECT}</td>
      *     <td>{@link Bundle#putStringArray}</td></tr>
      *     <tr><td>{@link RestrictionEntry#TYPE_INTEGER}</td><td>{@link Bundle#putInt}</td></tr>
      *     <tr><td>{@link RestrictionEntry#TYPE_STRING}</td><td>{@link Bundle#putString}</td></tr>
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 43cc63b..a59f429 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -273,10 +273,10 @@
     public static final int FLAG_RESUME_WHILE_PAUSING = 0x4000;
     /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
-     * by the primary user.  Only works with broadcast receivers.  Set from the
-     * android.R.attr#primaryUserOnly attribute.
+     * by the system user.  Only works with broadcast receivers.  Set from the
+     * android.R.attr#systemUserOnly attribute.
      */
-    public static final int FLAG_PRIMARY_USER_ONLY = 0x20000000;
+    public static final int FLAG_SYSTEM_USER_ONLY = 0x20000000;
     /**
      * Bit in {@link #flags}: If set, a single instance of the receiver will
      * run for all users on the device.  Set from the
@@ -698,6 +698,8 @@
      */
     public int lockTaskLaunchMode;
 
+    public InitialLayout initialLayout;
+
     public ActivityInfo() {
     }
 
@@ -717,6 +719,7 @@
         maxRecents = orig.maxRecents;
         resizeable = orig.resizeable;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
+        initialLayout = orig.initialLayout;
     }
 
     /**
@@ -763,9 +766,14 @@
         }
         pw.println(prefix + "resizeable=" + resizeable + " lockTaskLaunchMode="
                 + lockTaskLaunchModeToString(lockTaskLaunchMode));
+        if (initialLayout != null) {
+            pw.println(prefix + "initialLayout=" + initialLayout.width + "|"
+                    + initialLayout.widthFraction + ", " + initialLayout.height + "|"
+                    + initialLayout.heightFraction + ", " + initialLayout.gravity);
+        }
         super.dumpBack(pw, prefix);
     }
-    
+
     public String toString() {
         return "ActivityInfo{"
             + Integer.toHexString(System.identityHashCode(this))
@@ -793,6 +801,16 @@
         dest.writeInt(maxRecents);
         dest.writeInt(resizeable ? 1 : 0);
         dest.writeInt(lockTaskLaunchMode);
+        if (initialLayout != null) {
+            dest.writeInt(1);
+            dest.writeInt(initialLayout.width);
+            dest.writeFloat(initialLayout.widthFraction);
+            dest.writeInt(initialLayout.height);
+            dest.writeFloat(initialLayout.heightFraction);
+            dest.writeInt(initialLayout.gravity);
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     public static final Parcelable.Creator<ActivityInfo> CREATOR
@@ -822,5 +840,33 @@
         maxRecents = source.readInt();
         resizeable = (source.readInt() == 1);
         lockTaskLaunchMode = source.readInt();
+        if (source.readInt() == 1) {
+            initialLayout = new InitialLayout(source);
+        }
+    }
+
+    public static final class InitialLayout {
+        public InitialLayout(int width, float widthFraction, int height, float heightFraction,
+                int gravity) {
+            this.width = width;
+            this.widthFraction = widthFraction;
+            this.height = height;
+            this.heightFraction = heightFraction;
+            this.gravity = gravity;
+        }
+
+        InitialLayout(Parcel source) {
+            width = source.readInt();
+            widthFraction = source.readFloat();
+            height = source.readInt();
+            heightFraction = source.readFloat();
+            gravity = source.readInt();
+        }
+
+        public final int width;
+        public final float widthFraction;
+        public final int height;
+        public final float heightFraction;
+        public final int gravity;
     }
 }
diff --git a/core/java/android/content/pm/AppsQueryHelper.java b/core/java/android/content/pm/AppsQueryHelper.java
new file mode 100644
index 0000000..56b3173
--- /dev/null
+++ b/core/java/android/content/pm/AppsQueryHelper.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm;
+
+import android.Manifest;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.ArraySet;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Helper class for querying installed applications using multiple criteria.
+ *
+ * @hide
+ */
+public class AppsQueryHelper {
+
+    /**
+     * Return apps without launcher icon
+     */
+    public static int GET_NON_LAUNCHABLE_APPS = 1;
+
+    /**
+     * Return apps with {@link android.Manifest.permission#INTERACT_ACROSS_USERS} permission
+     */
+    public static int GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM = 1 << 1;
+
+    private final Context mContext;
+    private List<ApplicationInfo> mAllApps;
+
+    public AppsQueryHelper(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * Return a List of all packages that satisfy a specified criteria.
+     * @param flags search flags. Use any combination of {@link #GET_NON_LAUNCHABLE_APPS},
+     * {@link #GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM}
+     * @param systemAppsOnly if true, only system apps will be returned
+     * @param user user, whose apps are queried
+     */
+    public List<String> queryApps(int flags, boolean systemAppsOnly, UserHandle user) {
+        boolean nonLaunchableApps = (flags & GET_NON_LAUNCHABLE_APPS) > 0;
+        boolean interactAcrossUsers = (flags & GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM) > 0;
+        if (mAllApps == null) {
+            mAllApps = getAllApps(user.getIdentifier());
+        }
+
+        List<String> result = new ArrayList<>();
+        if (flags == 0) {
+            final int allAppsSize = mAllApps.size();
+            for (int i = 0; i < allAppsSize; i++) {
+                final ApplicationInfo appInfo = mAllApps.get(i);
+                if (systemAppsOnly && !appInfo.isSystemApp()) {
+                    continue;
+                }
+                result.add(appInfo.packageName);
+            }
+            return result;
+        }
+
+        if (nonLaunchableApps) {
+            Intent intent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
+            final List<ResolveInfo> resolveInfos = queryIntentActivitiesAsUser(intent,
+                    user.getIdentifier());
+
+            ArraySet<String> appsWithLaunchers = new ArraySet<>();
+            final int resolveInfosSize = resolveInfos.size();
+            for (int i = 0; i < resolveInfosSize; i++) {
+                appsWithLaunchers.add(resolveInfos.get(i).activityInfo.packageName);
+            }
+            final int allAppsSize = mAllApps.size();
+            for (int i = 0; i < allAppsSize; i++) {
+                final ApplicationInfo appInfo = mAllApps.get(i);
+                if (systemAppsOnly && !appInfo.isSystemApp()) {
+                    continue;
+                }
+                final String packageName = appInfo.packageName;
+                if (!appsWithLaunchers.contains(packageName)) {
+                    result.add(packageName);
+                }
+            }
+        }
+
+        if (interactAcrossUsers) {
+            final List<PackageInfo> packagesHoldingPermissions = getPackagesHoldingPermission(
+                    Manifest.permission.INTERACT_ACROSS_USERS, user.getIdentifier());
+            final int packagesHoldingPermissionsSize = packagesHoldingPermissions.size();
+            for (int i = 0; i < packagesHoldingPermissionsSize; i++) {
+                PackageInfo packageInfo = packagesHoldingPermissions.get(i);
+                if (systemAppsOnly && !packageInfo.applicationInfo.isSystemApp()) {
+                    continue;
+                }
+                if (!result.contains(packageInfo.packageName)) {
+                    result.add(packageInfo.packageName);
+                }
+            }
+        }
+
+        return result;
+    }
+
+    @VisibleForTesting
+    @SuppressWarnings("unchecked")
+    protected List<ApplicationInfo> getAllApps(int userId) {
+        try {
+            return AppGlobals.getPackageManager().getInstalledApplications(
+                    PackageManager.GET_UNINSTALLED_PACKAGES
+                            | PackageManager.GET_DISABLED_COMPONENTS, userId).getList();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package manager has died", e);
+        }
+    }
+
+    @VisibleForTesting
+    protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
+        return mContext.getPackageManager()
+                .queryIntentActivitiesAsUser(intent, PackageManager.GET_DISABLED_COMPONENTS
+                        | PackageManager.GET_UNINSTALLED_PACKAGES, userId);
+    }
+
+    @VisibleForTesting
+    @SuppressWarnings("unchecked")
+    protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+        try {
+            return AppGlobals.getPackageManager().getPackagesHoldingPermissions(new String[]{perm},
+                    0, userId).getList();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Package manager has died", e);
+        }
+    }
+}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 924df1b..968f9b2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -50,6 +50,7 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.Gravity;
 
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
@@ -3137,8 +3138,8 @@
             a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
         }
 
-        if (sa.getBoolean(R.styleable.AndroidManifestActivity_primaryUserOnly, false)) {
-            a.info.flags |= ActivityInfo.FLAG_PRIMARY_USER_ONLY;
+        if (sa.getBoolean(R.styleable.AndroidManifestActivity_systemUserOnly, false)) {
+            a.info.flags |= ActivityInfo.FLAG_SYSTEM_USER_ONLY;
         }
 
         if (!receiver) {
@@ -3260,10 +3261,12 @@
                     owner.preferredActivityFilters.add(intent);
                 }
             } else if (parser.getName().equals("meta-data")) {
-                if ((a.metaData=parseMetaData(res, parser, attrs, a.metaData,
+                if ((a.metaData = parseMetaData(res, parser, attrs, a.metaData,
                         outError)) == null) {
                     return null;
                 }
+            } else if (!receiver && parser.getName().equals("initial-layout")) {
+                parseInitialLayout(res, attrs, a);
             } else {
                 if (!RIGID_PARSER) {
                     Slog.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
@@ -3296,6 +3299,43 @@
         return a;
     }
 
+    private void parseInitialLayout(Resources res, AttributeSet attrs, Activity a) {
+        TypedArray sw = res.obtainAttributes(attrs,
+                com.android.internal.R.styleable.AndroidManifestInitialLayout);
+        int width = -1;
+        float widthFraction = -1f;
+        int height = -1;
+        float heightFraction = -1f;
+        final int widthType = sw.getType(
+                com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth);
+        if (widthType == TypedValue.TYPE_FRACTION) {
+            widthFraction = sw.getFraction(
+                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+                    1, 1, -1);
+        } else if (widthType == TypedValue.TYPE_DIMENSION) {
+            width = sw.getDimensionPixelSize(
+                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityWidth,
+                    -1);
+        }
+        final int heightType = sw.getType(
+                com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight);
+        if (heightType == TypedValue.TYPE_FRACTION) {
+            heightFraction = sw.getFraction(
+                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+                    1, 1, -1);
+        } else if (heightType == TypedValue.TYPE_DIMENSION) {
+            height = sw.getDimensionPixelSize(
+                    com.android.internal.R.styleable.AndroidManifestInitialLayout_activityHeight,
+                    -1);
+        }
+        int gravity = sw.getInt(
+                com.android.internal.R.styleable.AndroidManifestInitialLayout_gravity,
+                Gravity.CENTER);
+        sw.recycle();
+        a.info.initialLayout = new ActivityInfo.InitialLayout(width, widthFraction,
+                height, heightFraction, gravity);
+    }
+
     private Activity parseActivityAlias(Package owner, Resources res,
             XmlPullParser parser, AttributeSet attrs, int flags, String[] outError)
             throws XmlPullParserException, IOException {
@@ -3375,6 +3415,7 @@
         info.uiOptions = target.info.uiOptions;
         info.parentActivityName = target.info.parentActivityName;
         info.maxRecents = target.info.maxRecents;
+        info.initialLayout = target.info.initialLayout;
 
         Activity a = new Activity(mParseActivityAliasArgs, info);
         if (outError[0] != null) {
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index dfd0f7d..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() {
@@ -129,6 +131,15 @@
     }
 
     /**
+     * Returns true if the user is a split system user.
+     * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
+     * the method always returns false.
+     */
+    public boolean isSystemOnly() {
+        return id == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();
+    }
+
+    /**
      * @return true if this user can be switched to.
      **/
     public boolean supportsSwitchTo() {
@@ -152,8 +163,9 @@
         }
         if (UserManager.isSplitSystemUser()) {
             return id != UserHandle.USER_SYSTEM;
+        } else {
+            return id == UserHandle.USER_SYSTEM;
         }
-        return id == UserHandle.USER_OWNER;
     }
 
     public UserInfo() {
@@ -196,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
@@ -219,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/Resources.java b/core/java/android/content/res/Resources.java
index ae92108..e29bd2c 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -20,6 +20,7 @@
 import android.annotation.ColorInt;
 import android.annotation.StyleRes;
 import android.annotation.StyleableRes;
+import android.graphics.drawable.DrawableInflater;
 import android.icu.text.PluralRules;
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.util.XmlUtils;
@@ -142,6 +143,9 @@
     private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
             new ConfigurationBoundResourceCache<>(this);
 
+    /** Used to inflate drawable objects from XML. */
+    private DrawableInflater mDrawableInflater;
+
     private TypedValue mTmpValue = new TypedValue();
     private boolean mPreloading;
 
@@ -150,6 +154,7 @@
     private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4];
 
     final AssetManager mAssets;
+    final ClassLoader mClassLoader;
     final DisplayMetrics mMetrics = new DisplayMetrics();
 
     private final Configuration mConfiguration = new Configuration();
@@ -204,6 +209,17 @@
     }
 
     /**
+     * @return the inflater used to create drawable objects
+     * @hide Pending API finalization.
+     */
+    public final DrawableInflater getDrawableInflater() {
+        if (mDrawableInflater == null) {
+            mDrawableInflater = new DrawableInflater(this, mClassLoader);
+        }
+        return mDrawableInflater;
+    }
+
+    /**
      * Used by AnimatorInflater.
      *
      * @hide
@@ -245,7 +261,7 @@
      *               selecting/computing resource values (optional).
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
-        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
     }
 
     /**
@@ -257,11 +273,15 @@
      * @param config Desired device configuration to consider when
      *               selecting/computing resource values (optional).
      * @param compatInfo this resource's compatibility info. Must not be null.
+     * @param classLoader class loader for the package used to load custom
+     *                    resource classes, may be {@code null} to use system
+     *                    class loader
      * @hide
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
-            CompatibilityInfo compatInfo) {
+            CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
         mAssets = assets;
+        mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
         mMetrics.setToDefaults();
         if (compatInfo != null) {
             mCompatibilityInfo = compatInfo;
@@ -2803,6 +2823,7 @@
 
     private Resources() {
         mAssets = AssetManager.getSystem();
+        mClassLoader = ClassLoader.getSystemClassLoader();
         // NOTE: Intentionally leaving this uninitialized (all values set
         // to zero), so that anyone who tries to do something that requires
         // metrics will get a very wrong value.
diff --git a/core/java/android/hardware/ICameraServiceProxy.aidl b/core/java/android/hardware/ICameraServiceProxy.aidl
index 0bb24bc..0e654d5 100644
--- a/core/java/android/hardware/ICameraServiceProxy.aidl
+++ b/core/java/android/hardware/ICameraServiceProxy.aidl
@@ -19,6 +19,8 @@
 /**
  * Binder interface for the camera service proxy running in system_server.
  *
+ * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
+ *
  * @hide
  */
 interface ICameraServiceProxy
@@ -27,4 +29,9 @@
      * Ping the service proxy to update the valid users for the camera service.
      */
     oneway void pingForUserUpdate();
+
+    /**
+     * Update the status of a camera device
+     */
+     oneway void notifyCameraState(String cameraId, int newCameraState);
 }
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 5583920..a2ef078 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1003,13 +1003,13 @@
     /**
      * <p>The orientation of the camera relative to the sensor
      * coordinate system.</p>
-     * <p>The four coefficients that describe the quarternion
+     * <p>The four coefficients that describe the quaternion
      * rotation from the Android sensor coordinate system to a
      * camera-aligned coordinate system where the X-axis is
      * aligned with the long side of the image sensor, the Y-axis
      * is aligned with the short side of the image sensor, and
      * the Z-axis is aligned with the optical axis of the sensor.</p>
-     * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+     * <p>To convert from the quaternion coefficients <code>(x,y,z,w)</code>
      * to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
      * amount <code>theta</code>, the following formulas can be used:</p>
      * <pre><code> theta = 2 * acos(w)
@@ -1018,7 +1018,7 @@
      * a_z = z / sin(theta/2)
      * </code></pre>
      * <p>To create a 3x3 rotation matrix that applies the rotation
-     * defined by this quarternion, the following matrix can be
+     * defined by this quaternion, the following matrix can be
      * used:</p>
      * <pre><code>R = [ 1 - 2y^2 - 2z^2,       2xy - 2zw,       2xz + 2yw,
      *            2xy + 2zw, 1 - 2x^2 - 2z^2,       2yz - 2xw,
@@ -1030,7 +1030,7 @@
      * <p>where <code>p</code> is in the device sensor coordinate system, and
      *  <code>p'</code> is in the camera-oriented coordinate system.</p>
      * <p><b>Units</b>:
-     * Quarternion coefficients</p>
+     * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      */
     @PublicKey
@@ -1052,13 +1052,13 @@
      * user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
      * <p>To transform a pixel coordinates between two cameras
      * facing the same direction, first the source camera
-     * android.lens.radialDistortion must be corrected for.  Then
-     * the source camera android.lens.intrinsicCalibration needs
+     * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for.  Then
+     * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
      * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
      * of the source camera, the translation of the source camera
      * relative to the destination camera, the
      * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
-     * finally the inverse of android.lens.intrinsicCalibration
+     * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
      * of the destination camera. This obtains a
      * radial-distortion-free coordinate in the destination
      * camera pixel coordinates.</p>
@@ -1069,7 +1069,9 @@
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -1115,7 +1117,7 @@
      * where <code>(0,0)</code> is the top-left of the
      * preCorrectionActiveArraySize rectangle. Once the pose and
      * intrinsic calibration transforms have been applied to a
-     * world point, then the android.lens.radialDistortion
+     * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
      * transform needs to be applied, and the result adjusted to
      * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
      * system (where <code>(0, 0)</code> is the top-left of the
@@ -1130,6 +1132,7 @@
      *
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
@@ -1156,7 +1159,7 @@
      * </code></pre>
      * <p>The pixel coordinates are defined in a normalized
      * coordinate system related to the
-     * android.lens.intrinsicCalibration calibration fields.
+     * {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} calibration fields.
      * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the
      * lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes
      * of both x and y coordinates are normalized to be 1 at the
@@ -1169,6 +1172,8 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      */
     @PublicKey
     public static final Key<float[]> LENS_RADIAL_DISTORTION =
@@ -2262,7 +2267,7 @@
      * {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize}.</p>
      * <p>The currently supported fields that correct for geometric distortion are:</p>
      * <ol>
-     * <li>android.lens.radialDistortion.</li>
+     * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}.</li>
      * </ol>
      * <p>If all of the geometric distortion fields are no-ops, this rectangle will be the same
      * as the post-distortion-corrected rectangle given in
@@ -2275,6 +2280,7 @@
      * <p><b>Units</b>: Pixel coordinates on the image sensor</p>
      * <p>This key is available on all devices.</p>
      *
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PIXEL_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 4a71aa0..20b0be1 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -480,8 +480,11 @@
      * the configurations in the tables below are also guaranteed for creating a reprocessable
      * capture session if the camera device supports YUV reprocessing or PRIVATE reprocessing.
      * However, not all output targets used to create a reprocessable session may be used in a
-     * {@link CaptureRequest} simultaneously. The guaranteed output targets that can be included
-     * in a {@link CaptureRequest} simultaneously are listed in the tables under
+     * {@link CaptureRequest} simultaneously. For devices that support only 1 output target in a
+     * reprocess {@link CaptureRequest}, submitting a reprocess {@link CaptureRequest} with multiple
+     * output targets will result in a {@link CaptureFailure}. For devices that support multiple
+     * output targets in a reprocess {@link CaptureRequest}, the guaranteed output targets that can
+     * be included in a {@link CaptureRequest} simultaneously are listed in the tables under
      * {@link #createCaptureSession createCaptureSession}. For example, with a FULL-capability
      * ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL} {@code == }
      * {@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) device that supports PRIVATE
@@ -532,8 +535,6 @@
      * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code RECORD}</td> <td></td><td id="rb"></td> <td>High-resolution ZSL in-app video processing with regular preview.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Maximum-resolution ZSL in-app processing with regular preview.</td> </tr>
      * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td></td><td id="rb"></td> <td>Maximum-resolution two-input ZSL in-app processing.</td> </tr>
-     * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code RECORD}</td> <td>{@code JPEG}</td><td id="rb">{@code RECORD}</td> <td>High-resolution ZSL in-app video processing and video snapshot with regular preview.</td> </tr>
-     * <tr> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code MAXIMUM}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Maximum-resolution two-input ZSL in-app processing with regular preview.</td> </tr>
      * <tr> <td>{@code PRIV}/{@code YUV}</td><td id="rb">{@code MAXIMUM}</td> <td>Same as input</td><td id="rb">{@code MAXIMUM}</td> <td>{@code PRIV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code YUV}</td><td id="rb">{@code PREVIEW}</td> <td>{@code JPEG}</td><td id="rb">{@code MAXIMUM}</td> <td>ZSL still capture and in-app processing.</td> </tr>
      * </table><br>
      * </p>
@@ -711,7 +712,9 @@
      * provide input images to camera device via {@link android.media.ImageWriter#queueInputImage}.
      * The application must use the capture result of one of those output images to create a
      * reprocess capture request so that the camera device can use the information to achieve
-     * optimal reprocess image quality.
+     * optimal reprocess image quality. For camera devices that support only 1 output
+     * {@link Surface}, submitting a reprocess {@link CaptureRequest} with multiple
+     * output targets will result in a {@link CaptureFailure}.
      *
      * @param inputResult The capture result of the output image or one of the output images used
      *                       to generate the reprocess input image for this capture request.
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c580083..35a1d96 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -647,8 +647,8 @@
      *   {@link android.hardware.camera2.CaptureResult }:<ul>
      * <li>{@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}</li>
      * <li>{@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}</li>
-     * <li>android.lens.intrinsicCalibration</li>
-     * <li>android.lens.radialDistortion</li>
+     * <li>{@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}</li>
+     * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
      * </ul>
      * </li>
      * <li>The {@link CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE android.depth.depthIsExclusive} entry is listed by this device.</li>
@@ -667,8 +667,10 @@
      *
      * @see CameraCharacteristics#DEPTH_DEPTH_IS_EXCLUSIVE
      * @see CameraCharacteristics#LENS_FACING
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
      */
     public static final int REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT = 8;
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index d5511c1..46eddb3 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2602,13 +2602,13 @@
     /**
      * <p>The orientation of the camera relative to the sensor
      * coordinate system.</p>
-     * <p>The four coefficients that describe the quarternion
+     * <p>The four coefficients that describe the quaternion
      * rotation from the Android sensor coordinate system to a
      * camera-aligned coordinate system where the X-axis is
      * aligned with the long side of the image sensor, the Y-axis
      * is aligned with the short side of the image sensor, and
      * the Z-axis is aligned with the optical axis of the sensor.</p>
-     * <p>To convert from the quarternion coefficients <code>(x,y,z,w)</code>
+     * <p>To convert from the quaternion coefficients <code>(x,y,z,w)</code>
      * to the axis of rotation <code>(a_x, a_y, a_z)</code> and rotation
      * amount <code>theta</code>, the following formulas can be used:</p>
      * <pre><code> theta = 2 * acos(w)
@@ -2617,7 +2617,7 @@
      * a_z = z / sin(theta/2)
      * </code></pre>
      * <p>To create a 3x3 rotation matrix that applies the rotation
-     * defined by this quarternion, the following matrix can be
+     * defined by this quaternion, the following matrix can be
      * used:</p>
      * <pre><code>R = [ 1 - 2y^2 - 2z^2,       2xy - 2zw,       2xz + 2yw,
      *            2xy + 2zw, 1 - 2x^2 - 2z^2,       2yz - 2xw,
@@ -2629,7 +2629,7 @@
      * <p>where <code>p</code> is in the device sensor coordinate system, and
      *  <code>p'</code> is in the camera-oriented coordinate system.</p>
      * <p><b>Units</b>:
-     * Quarternion coefficients</p>
+     * Quaternion coefficients</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      */
     @PublicKey
@@ -2651,13 +2651,13 @@
      * user's perspective) will report <code>(0.03, 0, 0)</code>.</p>
      * <p>To transform a pixel coordinates between two cameras
      * facing the same direction, first the source camera
-     * android.lens.radialDistortion must be corrected for.  Then
-     * the source camera android.lens.intrinsicCalibration needs
+     * {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion} must be corrected for.  Then
+     * the source camera {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} needs
      * to be applied, followed by the {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}
      * of the source camera, the translation of the source camera
      * relative to the destination camera, the
      * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} of the destination camera, and
-     * finally the inverse of android.lens.intrinsicCalibration
+     * finally the inverse of {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration}
      * of the destination camera. This obtains a
      * radial-distortion-free coordinate in the destination
      * camera pixel coordinates.</p>
@@ -2668,7 +2668,9 @@
      * <p><b>Units</b>: Meters</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      * @see CameraCharacteristics#LENS_POSE_ROTATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      */
     @PublicKey
     public static final Key<float[]> LENS_POSE_TRANSLATION =
@@ -2714,7 +2716,7 @@
      * where <code>(0,0)</code> is the top-left of the
      * preCorrectionActiveArraySize rectangle. Once the pose and
      * intrinsic calibration transforms have been applied to a
-     * world point, then the android.lens.radialDistortion
+     * world point, then the {@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}
      * transform needs to be applied, and the result adjusted to
      * be in the {@link CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE android.sensor.info.activeArraySize} coordinate
      * system (where <code>(0, 0)</code> is the top-left of the
@@ -2729,6 +2731,7 @@
      *
      * @see CameraCharacteristics#LENS_POSE_ROTATION
      * @see CameraCharacteristics#LENS_POSE_TRANSLATION
+     * @see CameraCharacteristics#LENS_RADIAL_DISTORTION
      * @see CameraCharacteristics#SENSOR_INFO_ACTIVE_ARRAY_SIZE
      * @see CameraCharacteristics#SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
      */
@@ -2755,7 +2758,7 @@
      * </code></pre>
      * <p>The pixel coordinates are defined in a normalized
      * coordinate system related to the
-     * android.lens.intrinsicCalibration calibration fields.
+     * {@link CameraCharacteristics#LENS_INTRINSIC_CALIBRATION android.lens.intrinsicCalibration} calibration fields.
      * Both <code>[x_i, y_i]</code> and <code>[x_c, y_c]</code> have <code>(0,0)</code> at the
      * lens optical center <code>[c_x, c_y]</code>. The maximum magnitudes
      * of both x and y coordinates are normalized to be 1 at the
@@ -2768,6 +2771,8 @@
      * <p><b>Units</b>:
      * Unitless coefficients.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     *
+     * @see CameraCharacteristics#LENS_INTRINSIC_CALIBRATION
      */
     @PublicKey
     public static final Key<float[]> LENS_RADIAL_DISTORTION =
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index e786707..fddfbde 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -338,6 +338,8 @@
                     } else {
                         sizedSurfaces.add(new Pair<>(output, s));
                     }
+                    // Lock down the size before configuration
+                    setSurfaceDimens(output, s.getWidth(), s.getHeight());
                 } catch (BufferQueueAbandonedException e) {
                     Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
                     return BAD_VALUE;
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index e71e49f..b8d6960 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1290,7 +1290,7 @@
         for (StreamConfiguration config : configurations) {
             int fmt = config.getFormat();
             if (fmt == format && config.isOutput() == output) {
-                if (output) {
+                if (output && mListHighResolution) {
                     // Filter slow high-res output formats; include for
                     // highRes, remove for !highRes
                     long duration = 0;
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 061fad9..7cff11b 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -395,7 +395,7 @@
      * 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
-     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult) is called, at
+     * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
      * which point the object is no longer valid. The operation can be canceled by using the
      * provided cancel object.
      *
diff --git a/core/java/android/hardware/location/ActivityRecognitionHardware.java b/core/java/android/hardware/location/ActivityRecognitionHardware.java
index 5d3953a..8acd1ff 100644
--- a/core/java/android/hardware/location/ActivityRecognitionHardware.java
+++ b/core/java/android/hardware/location/ActivityRecognitionHardware.java
@@ -30,20 +30,34 @@
  * @hide
  */
 public class ActivityRecognitionHardware extends IActivityRecognitionHardware.Stub {
-    private static final String TAG = "ActivityRecognitionHardware";
+    private static final String TAG = "ActivityRecognitionHW";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+    private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+            + HARDWARE_PERMISSION + "' not granted to access ActivityRecognitionHardware";
+
     private static final int INVALID_ACTIVITY_TYPE = -1;
     private static final int NATIVE_SUCCESS_RESULT = 0;
+    private static final int EVENT_TYPE_DISABLED = 0;
+    private static final int EVENT_TYPE_ENABLED = 1;
 
-    private static ActivityRecognitionHardware sSingletonInstance = null;
+    /**
+     * Contains the number of supported Event Types.
+     *
+     * NOTE: increment this counter every time a new EVENT_TYPE_ is added to
+     *       com.android.location.provider.ActivityRecognitionProvider
+     */
+    private static final int EVENT_TYPE_COUNT = 3;
+
+    private static ActivityRecognitionHardware sSingletonInstance;
     private static final Object sSingletonInstanceLock = new Object();
 
     private final Context mContext;
+    private final int mSupportedActivitiesCount;
     private final String[] mSupportedActivities;
-
-    private final RemoteCallbackList<IActivityRecognitionHardwareSink> mSinks =
-            new RemoteCallbackList<IActivityRecognitionHardwareSink>();
+    private final int[][] mSupportedActivitiesEnabledEvents;
+    private final SinkList mSinks = new SinkList();
 
     private static class Event {
         public int activity;
@@ -56,6 +70,8 @@
 
         mContext = context;
         mSupportedActivities = fetchSupportedActivities();
+        mSupportedActivitiesCount = mSupportedActivities.length;
+        mSupportedActivitiesEnabledEvents = new int[mSupportedActivitiesCount][EVENT_TYPE_COUNT];
     }
 
     public static ActivityRecognitionHardware getInstance(Context context) {
@@ -107,7 +123,11 @@
         }
 
         int result = nativeEnableActivityEvent(activityType, eventType, reportLatencyNs);
-        return result == NATIVE_SUCCESS_RESULT;
+        if (result == NATIVE_SUCCESS_RESULT) {
+            mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_ENABLED;
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -120,7 +140,11 @@
         }
 
         int result = nativeDisableActivityEvent(activityType, eventType);
-        return result == NATIVE_SUCCESS_RESULT;
+        if (result == NATIVE_SUCCESS_RESULT) {
+            mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED;
+            return true;
+        }
+        return false;
     }
 
     @Override
@@ -135,7 +159,7 @@
      */
     private void onActivityChanged(Event[] events) {
         if (events == null || events.length == 0) {
-            Log.d(TAG, "No events to broadcast for onActivityChanged.");
+            if (DEBUG) Log.d(TAG, "No events to broadcast for onActivityChanged.");
             return;
         }
 
@@ -161,7 +185,6 @@
             }
         }
         mSinks.finishBroadcast();
-
     }
 
     private String getActivityName(int activityType) {
@@ -193,10 +216,7 @@
     }
 
     private void checkPermissions() {
-        String message = String.format(
-                "Permission '%s' not granted to access ActivityRecognitionHardware",
-                HARDWARE_PERMISSION);
-        mContext.enforceCallingPermission(HARDWARE_PERMISSION, message);
+        mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
     }
 
     private String[] fetchSupportedActivities() {
@@ -208,6 +228,39 @@
         return new String[0];
     }
 
+    private class SinkList extends RemoteCallbackList<IActivityRecognitionHardwareSink> {
+        @Override
+        public void onCallbackDied(IActivityRecognitionHardwareSink callback) {
+            int callbackCount = mSinks.getRegisteredCallbackCount();
+            if (DEBUG) Log.d(TAG, "RegisteredCallbackCount: " + callbackCount);
+            if (callbackCount != 0) {
+                return;
+            }
+            // currently there is only one client for this, so if all its sinks have died, we clean
+            // up after them, this ensures that the AR HAL is not out of sink
+            for (int activity = 0; activity < mSupportedActivitiesCount; ++activity) {
+                for (int event = 0; event < EVENT_TYPE_COUNT; ++event) {
+                    disableActivityEventIfEnabled(activity, event);
+                }
+            }
+        }
+
+        private void disableActivityEventIfEnabled(int activityType, int eventType) {
+            if (mSupportedActivitiesEnabledEvents[activityType][eventType] != EVENT_TYPE_ENABLED) {
+                return;
+            }
+
+            int result = nativeDisableActivityEvent(activityType, eventType);
+            mSupportedActivitiesEnabledEvents[activityType][eventType] = EVENT_TYPE_DISABLED;
+            String message = String.format(
+                    "DisableActivityEvent: activityType=%d, eventType=%d, result=%d",
+                    activityType,
+                    eventType,
+                    result);
+            Log.e(TAG, message);
+        }
+    }
+
     // native bindings
     static { nativeClassInit(); }
 
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 3b3ee52..a23a6cb 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -70,6 +70,8 @@
      * <li> {@link #USB_FUNCTION_MIDI} boolean extra indicating whether the
      * MIDI function is enabled
      * </ul>
+     * If the sticky intent has not been found, that indicates USB is disconnected,
+     * USB is not configued, MTP function is enabled, and all the other functions are disabled.
      *
      * {@hide}
      */
@@ -592,7 +594,7 @@
 
     /** @hide */
     public static String addFunction(String functions, String function) {
-        if ("none".equals(functions)) {
+        if (USB_FUNCTION_NONE.equals(functions)) {
             return function;
         }
         if (!containsFunction(functions, function)) {
@@ -613,7 +615,7 @@
             }
         }
         if (split.length == 1 && split[0] == null) {
-            return "none";
+            return USB_FUNCTION_NONE;
         }
         StringBuilder builder = new StringBuilder();
         for (int i = 0; i < split.length; i++) {
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a4e6219..ec0cc6d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1038,11 +1038,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/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java
index 29daf35..ec76b8a 100644
--- a/core/java/android/net/NetworkScorerAppManager.java
+++ b/core/java/android/net/NetworkScorerAppManager.java
@@ -94,8 +94,9 @@
 
         PackageManager pm = context.getPackageManager();
         // Only apps installed under the primary user of the device can be scorers.
+        // TODO: http://b/23422763
         List<ResolveInfo> receivers =
-                pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_OWNER);
+                pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM);
         for (ResolveInfo receiver : receivers) {
             // This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo
             final ActivityInfo receiverInfo = receiver.activityInfo;
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 80169a9..4ad9d6d 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.
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/service/notification/Condition.java b/core/java/android/service/notification/Condition.java
index 80bdbf1..2c7bf65 100644
--- a/core/java/android/service/notification/Condition.java
+++ b/core/java/android/service/notification/Condition.java
@@ -16,7 +16,6 @@
 
 package android.service.notification;
 
-import android.annotation.SystemApi;
 import android.content.Context;
 import android.net.Uri;
 import android.os.Parcel;
@@ -26,10 +25,7 @@
 
 /**
  * Condition information from condition providers.
- *
- * @hide
  */
-@SystemApi
 public class Condition implements Parcelable {
 
     public static final String SCHEME = "condition";
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index 03ee726..2a8fb2c 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -17,9 +17,9 @@
 package android.service.notification;
 
 import android.annotation.SdkConstant;
-import android.annotation.SystemApi;
 import android.app.INotificationManager;
 import android.app.Service;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -33,7 +33,10 @@
  * A service that provides conditions about boolean state.
  * <p>To extend this class, you must declare the service in your manifest file with
  * the {@link android.Manifest.permission#BIND_CONDITION_PROVIDER_SERVICE} permission
- * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
+ * and include an intent filter with the {@link #SERVICE_INTERFACE} action. If you want users to be
+ * able to create and update conditions for this service to monitor, include the
+ * {@link #META_DATA_RULE_TYPE}, {@link #META_DATA_DEFAULT_CONDITION_ID}, and
+ * {@link #META_DATA_CONFIGURATION_ACTIVITY} tags. For example:</p>
  * <pre>
  * &lt;service android:name=".MyConditionProvider"
  *          android:label="&#64;string/service_name"
@@ -41,11 +44,21 @@
  *     &lt;intent-filter>
  *         &lt;action android:name="android.service.notification.ConditionProviderService" />
  *     &lt;/intent-filter>
+ *     &lt;meta-data
+ *               android:name="android.service.zen.automatic.ruleType"
+ *               android:value="@string/my_condition_rule">
+ *           &lt;/meta-data>
+ *           &lt;meta-data
+ *               android:name="android.service.zen.automatic.defaultConditionId"
+ *               android:value="condition://com.my.package/mycondition">
+ *           &lt;/meta-data>
+ *           &lt;meta-data
+ *               android:name="android.service.zen.automatic.configurationActivity"
+ *               android:value="com.my.package/.MyConditionConfigurationActivity">
+ *           &lt;/meta-data>
  * &lt;/service></pre>
  *
- * @hide
  */
-@SystemApi
 public abstract class ConditionProviderService extends Service {
     private final String TAG = ConditionProviderService.class.getSimpleName()
             + "[" + getClass().getSimpleName() + "]";
@@ -62,9 +75,63 @@
     public static final String SERVICE_INTERFACE
             = "android.service.notification.ConditionProviderService";
 
+    /**
+     * The name of the {@code meta-data} tag containing a localized name of the type of zen rules
+     * provided by this service.
+     */
+    public static final String META_DATA_RULE_TYPE = "android.service.zen.automatic.ruleType";
+
+    /**
+     * The name of the {@code meta-data} tag containing a default Condition {@link Uri} that can
+     * be parsed by this service.
+     */
+    public static final String META_DATA_DEFAULT_CONDITION_ID =
+            "android.service.zen.automatic.defaultConditionId";
+
+    /**
+     * The name of the {@code meta-data} tag containing the {@link ComponentName} of an activity
+     * that allows users to configure the conditions provided by this service.
+     */
+    public static final String META_DATA_CONFIGURATION_ACTIVITY =
+            "android.service.zen.automatic.configurationActivity";
+
+    /**
+     * A condition {@link Uri} extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}. If the
+     * condition Uri is modified by that activity, it must be included in the result Intent extras
+     * in order to be persisted.
+     */
+    public static final String EXTRA_CONDITION_ID = "android.content.automatic.conditionId";
+
+    /**
+     * A String rule name extra passed to {@link #META_DATA_CONFIGURATION_ACTIVITY}. This extra is
+     * informative only, and will be ignored if included in the result Intent extras.
+     */
+    public static final String EXTRA_RULE_NAME = "android.content.automatic.ruleName";
+
+    /**
+     * Called when this service is connected.
+     */
     abstract public void onConnected();
+
+    /**
+     * Called when the system wants to know the state of Conditions managed by this provider.
+     *
+     * Implementations should evaluate the state of all subscribed conditions, and provide updates
+     * by calling {@link #notifyCondition(Condition)} or {@link #notifyConditions(Condition...)}.
+     * @param relevance
+     */
     abstract public void onRequestConditions(int relevance);
+
+    /**
+     * Called by the system when there is a new {@link Condition} to be managed by this provider.
+     * @param conditionId the Uri describing the criteria of the condition.
+     */
     abstract public void onSubscribe(Uri conditionId);
+
+    /**
+     * Called by the system when a {@link Condition} has been deleted.
+     * @param conditionId the Uri describing the criteria of the deleted condition.
+     */
     abstract public void onUnsubscribe(Uri conditionId);
 
     private final INotificationManager getNotificationInterface() {
@@ -75,11 +142,19 @@
         return mNoMan;
     }
 
+    /**
+     * Informs the notification manager that the state of a Condition has changed.
+     * @param condition the condition that has changed.
+     */
     public final void notifyCondition(Condition condition) {
         if (condition == null) return;
         notifyConditions(new Condition[]{ condition });
     }
 
+    /**
+     * Informs the notification manager that the state of one or more Conditions has changed.
+     * @param conditions the changed conditions.
+     */
     public final void notifyConditions(Condition... conditions) {
         if (!isBound() || conditions == null) return;
         try {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index db19f7a..6310570 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -118,7 +118,7 @@
     public boolean allowEvents = DEFAULT_ALLOW_EVENTS;
     public int allowCallsFrom = DEFAULT_SOURCE;
     public int allowMessagesFrom = DEFAULT_SOURCE;
-    public int user = UserHandle.USER_OWNER;
+    public int user = UserHandle.USER_SYSTEM;
 
     public ZenRule manualRule;
     public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
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/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 4d8a7d0..49cb8e2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -462,7 +462,7 @@
 
     /**
      * Returns the length that the specified CharSequence would have if
-     * spaces and control characters were trimmed from the start and end,
+     * spaces and ASCII control characters were trimmed from the start and end,
      * as by {@link String#trim}.
      */
     public static int getTrimmedLength(CharSequence s) {
@@ -505,7 +505,13 @@
         return false;
     }
 
-    // XXX currently this only reverses chars, not spans
+    /*
+     * @deprecated
+     * Do not use. This function only reverses individual {@code char}s and not their associated
+     * spans. It doesn't support surrogate pairs (that correspond to non-BMP code points),
+     * combining sequences or conjuncts either.
+     */
+    @Deprecated
     public static CharSequence getReverse(CharSequence source,
                                           int start, int end) {
         return new Reverser(source, start, end);
@@ -1470,8 +1476,9 @@
      */
     public static boolean isDigitsOnly(CharSequence str) {
         final int len = str.length();
-        for (int i = 0; i < len; i++) {
-            if (!Character.isDigit(str.charAt(i))) {
+        for (int cp, i = 0; i < len; i += Character.charCount(cp)) {
+            cp = Character.codePointAt(str, i);
+            if (!Character.isDigit(cp)) {
                 return false;
             }
         }
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index a53da09..9f5dfa6 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -98,7 +98,8 @@
 
     /** {@hide} */
     public static BytesResult formatBytes(Resources res, long sizeBytes, int flags) {
-        float result = sizeBytes;
+        final boolean isNegative = (sizeBytes < 0);
+        float result = isNegative ? -sizeBytes : sizeBytes;
         int suffix = com.android.internal.R.string.byteShort;
         long mult = 1;
         if (result > 900) {
@@ -154,9 +155,13 @@
                 roundFormat = "%.2f";
             }
         }
+
+        if (isNegative) {
+            result = -result;
+        }
         final String roundedString = String.format(roundFormat, result);
 
-        // Note this might overflow if result >= Long.MAX_VALUE / 100, but that's like 80PB so
+        // Note this might overflow if abs(result) >= Long.MAX_VALUE / 100, but that's like 80PB so
         // it's okay (for now)...
         final long roundedBytes =
                 (flags & FLAG_CALCULATE_ROUNDED) == 0 ? 0
diff --git a/core/java/android/view/ContextThemeWrapper.java b/core/java/android/view/ContextThemeWrapper.java
index ce50091..ea0873d 100644
--- a/core/java/android/view/ContextThemeWrapper.java
+++ b/core/java/android/view/ContextThemeWrapper.java
@@ -19,12 +19,13 @@
 import android.annotation.StyleRes;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.content.res.AssetManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 
 /**
- * A ContextWrapper that allows you to modify the theme from what is in the 
- * wrapped context. 
+ * A context wrapper that allows you to modify or replace the theme of the
+ * wrapped context.
  */
 public class ContextThemeWrapper extends ContextWrapper {
     private int mThemeResource;
@@ -33,15 +34,42 @@
     private Configuration mOverrideConfiguration;
     private Resources mResources;
 
+    /**
+     * Creates a new context wrapper with no theme and no base context.
+     * <p>
+     * <stong>Note:</strong> A base context <strong>must</strong> be attached
+     * using {@link #attachBaseContext(Context)} before calling any other
+     * method on the newly constructed context wrapper.
+     */
     public ContextThemeWrapper() {
         super(null);
     }
 
+    /**
+     * Creates a new context wrapper with the specified theme.
+     * <p>
+     * The specified theme will be applied on top of the base context's theme.
+     * Any attributes not explicitly defined in the theme identified by
+     * <var>themeResId</var> will retain their original values.
+     *
+     * @param base the base context
+     * @param themeResId the resource ID of the theme to be applied on top of
+     *                   the base context's theme
+     */
     public ContextThemeWrapper(Context base, @StyleRes int themeResId) {
         super(base);
         mThemeResource = themeResId;
     }
 
+    /**
+     * Creates a new context wrapper with the specified theme.
+     * <p>
+     * Unlike {@link #ContextThemeWrapper(Context, int)}, the theme passed to
+     * this constructor will completely replace the base context's theme.
+     *
+     * @param base the base context
+     * @param theme the theme against which resources should be inflated
+     */
     public ContextThemeWrapper(Context base, Resources.Theme theme) {
         super(base);
         mTheme = theme;
@@ -60,11 +88,12 @@
      * information.
      *
      * <p>This method can only be called once, and must be called before any
-     * calls to {@link #getResources()} are made.
+     * calls to {@link #getResources()} or {@link #getAssets()} are made.
      */
     public void applyOverrideConfiguration(Configuration overrideConfiguration) {
         if (mResources != null) {
-            throw new IllegalStateException("getResources() has already been called");
+            throw new IllegalStateException(
+                    "getResources() or getAssets() has already been called");
         }
         if (mOverrideConfiguration != null) {
             throw new IllegalStateException("Override configuration has already been set");
@@ -73,20 +102,25 @@
     }
 
     @Override
-    public Resources getResources() {
-        if (mResources != null) {
-            return mResources;
-        }
-        if (mOverrideConfiguration == null) {
-            mResources = super.getResources();
-            return mResources;
-        } else {
-            Context resc = createConfigurationContext(mOverrideConfiguration);
-            mResources = resc.getResources();
-            return mResources;
-        }
+    public AssetManager getAssets() {
+        // Ensure we're returning assets with the correct configuration.
+        return getResources().getAssets();
     }
-    
+
+    @Override
+    public Resources getResources() {
+        if (mResources == null) {
+            if (mOverrideConfiguration == null) {
+                mResources = super.getResources();
+            } else {
+                final Context resContext = createConfigurationContext(mOverrideConfiguration);
+                mResources = resContext.getResources();
+            }
+        }
+
+        return mResources;
+    }
+
     @Override
     public void setTheme(int resid) {
         if (mThemeResource != resid) {
@@ -94,14 +128,15 @@
             initializeTheme();
         }
     }
-    
+
     /** @hide */
     @Override
     public int getThemeResId() {
         return mThemeResource;
     }
 
-    @Override public Resources.Theme getTheme() {
+    @Override
+    public Resources.Theme getTheme() {
         if (mTheme != null) {
             return mTheme;
         }
@@ -113,7 +148,8 @@
         return mTheme;
     }
 
-    @Override public Object getSystemService(String name) {
+    @Override
+    public Object getSystemService(String name) {
         if (LAYOUT_INFLATER_SERVICE.equals(name)) {
             if (mInflater == null) {
                 mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
@@ -122,27 +158,27 @@
         }
         return getBaseContext().getSystemService(name);
     }
-    
+
     /**
      * Called by {@link #setTheme} and {@link #getTheme} to apply a theme
-     * resource to the current Theme object.  Can override to change the
-     * default (simple) behavior.  This method will not be called in multiple
+     * resource to the current Theme object. May be overridden to change the
+     * default (simple) behavior. This method will not be called in multiple
      * threads simultaneously.
      *
-     * @param theme The Theme object being modified.
-     * @param resid The theme style resource being applied to <var>theme</var>.
-     * @param first Set to true if this is the first time a style is being
-     *              applied to <var>theme</var>.
+     * @param theme the theme being modified
+     * @param resId the style resource being applied to <var>theme</var>
+     * @param first {@code true} if this is the first time a style is being
+     *              applied to <var>theme</var>
      */
-    protected void onApplyThemeResource(Resources.Theme theme, int resid, boolean first) {
-        theme.applyStyle(resid, true);
+    protected void onApplyThemeResource(Resources.Theme theme, int resId, boolean first) {
+        theme.applyStyle(resId, true);
     }
 
     private void initializeTheme() {
         final boolean first = mTheme == null;
         if (first) {
             mTheme = getResources().newTheme();
-            Resources.Theme theme = getBaseContext().getTheme();
+            final Resources.Theme theme = getBaseContext().getTheme();
             if (theme != null) {
                 mTheme.setTo(theme);
             }
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 948cec7..080ed9a 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -20,12 +20,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.CanvasProperty;
-import android.graphics.NinePatch;
 import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.Picture;
-import android.graphics.Rect;
-import android.graphics.RectF;
 import android.util.Pools.SynchronizedPool;
 
 /**
@@ -206,16 +201,12 @@
      * Draws the specified layer onto this canvas.
      *
      * @param layer The layer to composite on this canvas
-     * @param x The left coordinate of the layer
-     * @param y The top coordinate of the layer
-     * @param paint The paint used to draw the layer
      */
-    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
-        layer.setLayerPaint(paint);
-        nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle(), x, y);
+    void drawHardwareLayer(HardwareLayer layer) {
+        nDrawLayer(mNativeCanvasWrapper, layer.getLayerHandle());
     }
 
-    private static native void nDrawLayer(long renderer, long layer, float x, float y);
+    private static native void nDrawLayer(long renderer, long layer);
 
     ///////////////////////////////////////////////////////////////////////////
     // Drawing
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 65ae8a6..692ca7b 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -150,8 +150,4 @@
     private static native void nSetSurfaceTexture(long layerUpdater,
             SurfaceTexture surface, boolean isAlreadyAttached);
     private static native void nUpdateSurfaceTexture(long layerUpdater);
-    private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
-            int left, int top, int right, int bottom);
-
-    private static native int nGetTexName(long layerUpdater);
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 197ea09..6b60be9 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -319,11 +319,25 @@
      */
     @Override
     public final void draw(Canvas canvas) {
-        // NOTE: Maintain this carefully (see View.java)
+        // NOTE: Maintain this carefully (see View#draw)
         mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
 
-        applyUpdate();
-        applyTransformMatrix();
+        /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
+        scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
+        properties (alpha, layer paint) affect all of the content of a TextureView. */
+
+        if (canvas.isHardwareAccelerated()) {
+            DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+
+            HardwareLayer layer = getHardwareLayer();
+            if (layer != null) {
+                applyUpdate();
+                applyTransformMatrix();
+
+                mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
+                displayListCanvas.drawHardwareLayer(layer);
+            }
+        }
     }
 
     /**
@@ -359,12 +373,7 @@
         invalidate(true);
     }
 
-    @Override
     HardwareLayer getHardwareLayer() {
-        // NOTE: Maintain these two lines very carefully (see View.java)
-        mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
-        mPrivateFlags &= ~PFLAG_DIRTY_MASK;
-
         if (mLayer == null) {
             if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
                 return null;
@@ -402,9 +411,6 @@
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
         }
 
-        applyUpdate();
-        applyTransformMatrix();
-
         return mLayer;
     }
 
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 a492518..16d9bf3 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -576,6 +576,53 @@
  * often used as a convenience to store data related to views in the views
  * themselves rather than by putting them in a separate structure.
  * </p>
+ * <p>
+ * Tags may be specified with character sequence values in layout XML as either
+ * a single tag using the {@link android.R.styleable#View_tag android:tag}
+ * attribute or multiple tags using the {@code &lt;tag&gt;} child element:
+ * <pre>
+ *     &ltView ...
+ *           android:tag="@string/mytag_value" /&gt;
+ *     &ltView ...&gt;
+ *         &lttag android:id="@+id/mytag"
+ *              android:value="@string/mytag_value" /&gt;
+ *     &lt/View>
+ * </pre>
+ * </p>
+ * <p>
+ * Tags may also be specified with arbitrary objects from code using
+ * {@link #setTag(Object)} or {@link #setTag(int, Object)}.
+ * </p>
+ *
+ * <a name="Themes"></a>
+ * <h3>Themes</h3>
+ * <p>
+ * By default, Views are created using the theme of the Context object supplied
+ * to their constructor; however, a different theme may be specified by using
+ * the {@link android.R.styleable#View_theme android:theme} attribute in layout
+ * XML or by passing a {@link ContextThemeWrapper} to the constructor from
+ * code.
+ * </p>
+ * <p>
+ * When the {@link android.R.styleable#View_theme android:theme} attribute is
+ * used in XML, the specified theme is applied on top of the inflation
+ * context's theme (see {@link LayoutInflater}) and used for the view itself as
+ * well as any child elements.
+ * </p>
+ * <p>
+ * In the following example, both views will be created using the Material dark
+ * color scheme; however, because an overlay theme is used which only defines a
+ * subset of attributes, the value of
+ * {@link android.R.styleable#Theme_colorAccent android:colorAccent} defined on
+ * the inflation context's theme (e.g. the Activity theme) will be preserved.
+ * <pre>
+ *     &ltLinearLayout
+ *             ...
+ *             android:theme="@android:theme/ThemeOverlay.Material.Dark"&gt;
+ *         &ltView ...&gt;
+ *     &lt/LinearLayout&gt;
+ * </pre>
+ * </p>
  *
  * <a name="Properties"></a>
  * <h3>Properties</h3>
@@ -699,6 +746,7 @@
  * @attr ref android.R.styleable#View_translationY
  * @attr ref android.R.styleable#View_translationZ
  * @attr ref android.R.styleable#View_visibility
+ * @attr ref android.R.styleable#View_theme
  *
  * @see android.view.ViewGroup
  */
@@ -753,6 +801,11 @@
     private static boolean sIgnoreMeasureCache = false;
 
     /**
+     * Ignore an optimization that skips unnecessary EXACTLY layout passes.
+     */
+    private static boolean sAlwaysRemeasureExactly = false;
+
+    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -3817,6 +3870,11 @@
             // specifically apps that use some popular open source libraries.
             sUseZeroUnspecifiedMeasureSpec = targetSdkVersion < M;
 
+            // Old versions of the platform would give different results from
+            // LinearLayout measurement passes using EXACTLY and non-EXACTLY
+            // modes, so we always need to run an additional EXACTLY pass.
+            sAlwaysRemeasureExactly = targetSdkVersion <= M;
+
             sCompatibilityDone = true;
         }
     }
@@ -15002,16 +15060,6 @@
     }
 
     /**
-     * If this View draws with a HardwareLayer, returns it.
-     * Otherwise returns null
-     *
-     * TODO: Only TextureView uses this, can we eliminate it?
-     */
-    HardwareLayer getHardwareLayer() {
-        return null;
-    }
-
-    /**
      * Destroys all hardware rendering resources. This method is invoked
      * when the system needs to reclaim resources. Upon execution of this
      * method, you should free any OpenGL resources created by the view.
@@ -15161,10 +15209,7 @@
             canvas.setHighContrastText(mAttachInfo.mHighContrastText);
 
             try {
-                final HardwareLayer layer = getHardwareLayer();
-                if (layer != null && layer.isValid()) {
-                    canvas.drawHardwareLayer(layer, 0, 0, mLayerPaint);
-                } else if (layerType == LAYER_TYPE_SOFTWARE) {
+                if (layerType == LAYER_TYPE_SOFTWARE) {
                     buildDrawingCache(true);
                     Bitmap cache = getDrawingCache(true);
                     if (cache != null) {
@@ -18785,17 +18830,27 @@
         long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL;
         if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2);
 
-        if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ||
-                widthMeasureSpec != mOldWidthMeasureSpec ||
-                heightMeasureSpec != mOldHeightMeasureSpec) {
+        final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT;
 
+        // Optimize layout by avoiding an extra EXACTLY pass when the view is
+        // already measured as the correct size. In API 23 and below, this
+        // extra pass is required to make LinearLayout re-distribute weight.
+        final boolean specChanged = widthMeasureSpec != mOldWidthMeasureSpec
+                || heightMeasureSpec != mOldHeightMeasureSpec;
+        final boolean isSpecExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY
+                && MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY;
+        final boolean matchesSpecSize = getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec)
+                && getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec);
+        final boolean needsLayout = specChanged
+                && (sAlwaysRemeasureExactly || !isSpecExactly || !matchesSpecSize);
+
+        if (forceLayout || needsLayout) {
             // first clears the measured dimension flag
             mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET;
 
             resolveRtlPropertiesIfNeeded();
 
-            int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 :
-                    mMeasureCache.indexOfKey(key);
+            int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key);
             if (cacheIndex < 0 || sIgnoreMeasureCache) {
                 // measure ourselves, this should set the measured dimension flag back
                 onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index aa20dfb..8bbaf36 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2276,6 +2276,9 @@
      */
     void outputDisplayList(View view) {
         view.mRenderNode.output();
+        if (mAttachInfo.mHardwareRenderer != null) {
+            ((ThreadedRenderer)mAttachInfo.mHardwareRenderer).serializeDisplayListTree();
+        }
     }
 
     /**
@@ -6519,6 +6522,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) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 1a9fb34..7a3d882 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -510,6 +510,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/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 7b4640b..a6d9932 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -120,6 +120,13 @@
     }
 
     /**
+      * An interface to be notified about hardware keyboard status.
+      */
+    public interface OnHardKeyboardStatusChangeListener {
+        public void onHardKeyboardStatusChange(boolean available);
+    }
+
+    /**
      * Request that the window manager call
      * {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
      * within a surface transaction at a later time.
@@ -231,4 +238,29 @@
      * @param listener The listener to register.
      */
     public abstract void registerAppTransitionListener(AppTransitionListener listener);
+
+    /**
+     * Retrieves a height of input method window.
+     */
+    public abstract int getInputMethodWindowVisibleHeight();
+
+    /**
+      * Saves last input method window for transition.
+      *
+      * Note that it is assumed that this method is called only by InputMethodManagerService.
+      */
+    public abstract void saveLastInputMethodWindowForTransition();
+
+    /**
+      * Returns true when the hardware keyboard is available.
+      */
+    public abstract boolean isHardKeyboardAvailable();
+
+    /**
+      * Sets the callback listener for hardware keyboard status changes.
+      *
+      * @param listener The listener to set.
+      */
+    public abstract void setOnHardKeyboardStatusChangeListener(
+        OnHardKeyboardStatusChangeListener listener);
 }
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index 6962711..0cc1b25 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -612,7 +612,7 @@
         View listItem = view;
         try {
             View v;
-            while (!(v = (View) listItem.getParent()).equals(this)) {
+            while ((v = (View) listItem.getParent()) != null && !v.equals(this)) {
                 listItem = v;
             }
         } catch (ClassCastException e) {
@@ -620,11 +620,13 @@
             return INVALID_POSITION;
         }
 
-        // Search the children for the list item
-        final int childCount = getChildCount();
-        for (int i = 0; i < childCount; i++) {
-            if (getChildAt(i).equals(listItem)) {
-                return mFirstPosition + i;
+        if (listItem != null) {
+            // Search the children for the list item
+            final int childCount = getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (getChildAt(i).equals(listItem)) {
+                    return mFirstPosition + i;
+                }
             }
         }
 
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 150b407..fddc40f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -107,6 +107,7 @@
 import android.widget.TextView.Drawables;
 import android.widget.TextView.OnEditorActionListener;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.GrowingArrayUtils;
 import com.android.internal.util.Preconditions;
@@ -2632,7 +2633,8 @@
         }
     }
 
-    private class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
+    @VisibleForTesting
+    public class SuggestionsPopupWindow extends PinnedPopupWindow implements OnItemClickListener {
         private static final int MAX_NUMBER_SUGGESTIONS = SuggestionSpan.SUGGESTIONS_MAX_SIZE;
         private static final int ADD_TO_DICTIONARY = -1;
         private static final int DELETE_TEXT = -2;
@@ -2798,6 +2800,11 @@
             return suggestionSpans;
         }
 
+        @VisibleForTesting
+        public ViewGroup getContentViewForTesting() {
+            return mContentView;
+        }
+
         @Override
         public void show() {
             if (!(mTextView.getText() instanceof Editable)) return;
@@ -5103,6 +5110,11 @@
         return 0 <= start && start <= end && end <= text.length();
     }
 
+    @VisibleForTesting
+    public SuggestionsPopupWindow getSuggestionsPopupWindowForTesting() {
+        return mSuggestionsPopupWindow;
+    }
+
     /**
      * An InputFilter that monitors text input to maintain undo history. It does not modify the
      * text being typed (and hence always returns null from the filter() method).
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 20fe61d..b53af0c 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -72,6 +72,8 @@
  */
 @RemoteView
 public class ImageView extends View {
+    private static final String LOG_TAG = "ImageView";
+
     // settable by the client
     private Uri mUri;
     private int mResource = 0;
@@ -87,7 +89,7 @@
     private boolean mHasColorFilter = false;
     private Xfermode mXfermode;
     private int mAlpha = 255;
-    private int mViewAlphaScale = 256;
+    private final int mViewAlphaScale = 256;
     private boolean mColorMod = false;
 
     private Drawable mDrawable = null;
@@ -105,8 +107,8 @@
     private Matrix mDrawMatrix = null;
 
     // Avoid allocations...
-    private RectF mTempSrc = new RectF();
-    private RectF mTempDst = new RectF();
+    private final RectF mTempSrc = new RectF();
+    private final RectF mTempDst = new RectF();
 
     private boolean mCropToPadding;
 
@@ -116,6 +118,9 @@
     // AdjustViewBounds behavior will be in compatibility mode for older apps.
     private boolean mAdjustViewBoundsCompat = false;
 
+    /** Whether to pass Resources when creating the source from a stream. */
+    private boolean mUseCorrectStreamDensity;
+
     private static final ScaleType[] sScaleTypeArray = {
         ScaleType.MATRIX,
         ScaleType.FIT_XY,
@@ -147,30 +152,21 @@
         initImageView();
 
         final TypedArray a = context.obtainStyledAttributes(
-                attrs, com.android.internal.R.styleable.ImageView, defStyleAttr, defStyleRes);
+                attrs, R.styleable.ImageView, defStyleAttr, defStyleRes);
 
-        Drawable d = a.getDrawable(com.android.internal.R.styleable.ImageView_src);
+        final Drawable d = a.getDrawable(R.styleable.ImageView_src);
         if (d != null) {
             setImageDrawable(d);
         }
 
-        mBaselineAlignBottom = a.getBoolean(
-                com.android.internal.R.styleable.ImageView_baselineAlignBottom, false);
+        mBaselineAlignBottom = a.getBoolean(R.styleable.ImageView_baselineAlignBottom, false);
+        mBaseline = a.getDimensionPixelSize(R.styleable.ImageView_baseline, -1);
 
-        mBaseline = a.getDimensionPixelSize(
-                com.android.internal.R.styleable.ImageView_baseline, -1);
+        setAdjustViewBounds(a.getBoolean(R.styleable.ImageView_adjustViewBounds, false));
+        setMaxWidth(a.getDimensionPixelSize(R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
+        setMaxHeight(a.getDimensionPixelSize(R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
 
-        setAdjustViewBounds(
-            a.getBoolean(com.android.internal.R.styleable.ImageView_adjustViewBounds,
-            false));
-
-        setMaxWidth(a.getDimensionPixelSize(
-                com.android.internal.R.styleable.ImageView_maxWidth, Integer.MAX_VALUE));
-        
-        setMaxHeight(a.getDimensionPixelSize(
-                com.android.internal.R.styleable.ImageView_maxHeight, Integer.MAX_VALUE));
-        
-        final int index = a.getInt(com.android.internal.R.styleable.ImageView_scaleType, -1);
+        final int index = a.getInt(R.styleable.ImageView_scaleType, -1);
         if (index >= 0) {
             setScaleType(sScaleTypeArray[index]);
         }
@@ -193,24 +189,26 @@
 
         applyImageTint();
 
-        final int alpha = a.getInt(com.android.internal.R.styleable.ImageView_drawableAlpha, 255);
+        final int alpha = a.getInt(R.styleable.ImageView_drawableAlpha, 255);
         if (alpha != 255) {
-            setAlpha(alpha);
+            setImageAlpha(alpha);
         }
 
         mCropToPadding = a.getBoolean(
-                com.android.internal.R.styleable.ImageView_cropToPadding, false);
-        
+                R.styleable.ImageView_cropToPadding, false);
+
         a.recycle();
 
         //need inflate syntax/reader for matrix
     }
 
     private void initImageView() {
-        mMatrix     = new Matrix();
-        mScaleType  = ScaleType.FIT_CENTER;
-        mAdjustViewBoundsCompat = mContext.getApplicationInfo().targetSdkVersion <=
-                Build.VERSION_CODES.JELLY_BEAN_MR1;
+        mMatrix = new Matrix();
+        mScaleType = ScaleType.FIT_CENTER;
+
+        final int targetSdkVersion = mContext.getApplicationInfo().targetSdkVersion;
+        mAdjustViewBoundsCompat = targetSdkVersion <= Build.VERSION_CODES.JELLY_BEAN_MR1;
+        mUseCorrectStreamDensity = targetSdkVersion > Build.VERSION_CODES.M;
     }
 
     @Override
@@ -258,7 +256,8 @@
     @Override
     public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         super.onPopulateAccessibilityEventInternal(event);
-        CharSequence contentDescription = getContentDescription();
+
+        final CharSequence contentDescription = getContentDescription();
         if (!TextUtils.isEmpty(contentDescription)) {
             event.getText().add(contentDescription);
         }
@@ -269,7 +268,7 @@
      * to preserve the aspect ratio of its drawable
      *
      * @return whether to adjust the bounds of this view
-     * to presrve the original aspect ratio of the drawable
+     * to preserve the original aspect ratio of the drawable
      *
      * @see #setAdjustViewBounds(boolean)
      *
@@ -291,7 +290,7 @@
      *
      * @param adjustViewBounds Whether to adjust the bounds of this view
      * to preserve the original aspect ratio of the drawable.
-     * 
+     *
      * @see #getAdjustViewBounds()
      *
      * @attr ref android.R.styleable#ImageView_adjustViewBounds
@@ -323,14 +322,14 @@
      * of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
      * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
      * layout params to WRAP_CONTENT.
-     * 
+     *
      * <p>
      * Note that this view could be still smaller than 100 x 100 using this approach if the original
      * image is small. To set an image to a fixed size, specify that size in the layout params and
      * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
      * the image within the bounds.
      * </p>
-     * 
+     *
      * @param maxWidth maximum width for this view
      *
      * @see #getMaxWidth()
@@ -361,14 +360,14 @@
      * maximum of 100 x 100 while preserving the original aspect ratio, do the following: 1) set
      * adjustViewBounds to true 2) set maxWidth and maxHeight to 100 3) set the height and width
      * layout params to WRAP_CONTENT.
-     * 
+     *
      * <p>
      * Note that this view could be still smaller than 100 x 100 using this approach if the original
      * image is small. To set an image to a fixed size, specify that size in the layout params and
      * then use {@link #setScaleType(android.widget.ImageView.ScaleType)} to determine how to fit
      * the image within the bounds.
      * </p>
-     * 
+     *
      * @param maxHeight maximum height for this view
      *
      * @see #getMaxHeight()
@@ -436,9 +435,7 @@
      */
     @android.view.RemotableViewMethod
     public void setImageURI(@Nullable Uri uri) {
-        if (mResource != 0 ||
-                (mUri != uri &&
-                 (uri == null || mUri == null || !uri.equals(mUri)))) {
+        if (mResource != 0 || (mUri != uri && (uri == null || mUri == null || !uri.equals(mUri)))) {
             updateDrawable(null);
             mResource = 0;
             mUri = uri;
@@ -457,7 +454,7 @@
 
     /**
      * Sets a drawable as the content of this ImageView.
-     * 
+     *
      * @param drawable the Drawable to set, or {@code null} to clear the
      *                 content
      */
@@ -577,7 +574,7 @@
 
     /**
      * Sets a Bitmap as the content of this ImageView.
-     * 
+     *
      * @param bm The bitmap to set
      */
     @android.view.RemotableViewMethod
@@ -609,7 +606,7 @@
     }
 
     /**
-     * Sets the image level, when it is constructed from a 
+     * Sets the image level, when it is constructed from a
      * {@link android.graphics.drawable.LevelListDrawable}.
      *
      * @param level The new level for the image.
@@ -675,7 +672,7 @@
          * From XML, use this syntax: <code>android:scaleType="centerInside"</code>.
          */
         CENTER_INSIDE (7);
-        
+
         ScaleType(int ni) {
             nativeInt = ni;
         }
@@ -685,9 +682,9 @@
     /**
      * Controls how the image should be resized or moved to match the size
      * of this ImageView.
-     * 
+     *
      * @param scaleType The desired scaling mode.
-     * 
+     *
      * @attr ref android.R.styleable#ImageView_scaleType
      */
     public void setScaleType(ScaleType scaleType) {
@@ -698,13 +695,13 @@
         if (mScaleType != scaleType) {
             mScaleType = scaleType;
 
-            setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);            
+            setWillNotCacheDrawing(mScaleType == ScaleType.CENTER);
 
             requestLayout();
             invalidate();
         }
     }
-    
+
     /**
      * Return the current scale type in use by this ImageView.
      *
@@ -734,7 +731,7 @@
      * Adds a transformation {@link Matrix} that is applied
      * to the view's drawable when it is drawn.  Allows custom scaling,
      * translation, and perspective distortion.
-     * 
+     *
      * @param matrix the transformation parameters in matrix form
      */
     public void setImageMatrix(Matrix matrix) {
@@ -787,8 +784,8 @@
             return;
         }
 
-        Resources rsrc = getResources();
-        if (rsrc == null) {
+        final Resources res = getResources();
+        if (res == null) {
             return;
         }
 
@@ -798,12 +795,12 @@
             try {
                 d = mContext.getDrawable(mResource);
             } catch (Exception e) {
-                Log.w("ImageView", "Unable to find resource: " + mResource, e);
+                Log.w(LOG_TAG, "Unable to find resource: " + mResource, e);
                 // Don't try again.
                 mUri = null;
             }
         } else if (mUri != null) {
-            String scheme = mUri.getScheme();
+            final String scheme = mUri.getScheme();
             if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
                 try {
                     // Load drawable through Resources, to get the source density information
@@ -811,31 +808,32 @@
                             mContext.getContentResolver().getResourceId(mUri);
                     d = r.r.getDrawable(r.id, mContext.getTheme());
                 } catch (Exception e) {
-                    Log.w("ImageView", "Unable to open content: " + mUri, e);
+                    Log.w(LOG_TAG, "Unable to open content: " + mUri, e);
                 }
             } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
                     || ContentResolver.SCHEME_FILE.equals(scheme)) {
                 InputStream stream = null;
                 try {
                     stream = mContext.getContentResolver().openInputStream(mUri);
-                    d = Drawable.createFromStream(stream, null);
+                    d = Drawable.createFromResourceStream(
+                            mUseCorrectStreamDensity ? res : null, null, stream, null);
                 } catch (Exception e) {
-                    Log.w("ImageView", "Unable to open content: " + mUri, e);
+                    Log.w(LOG_TAG, "Unable to open content: " + mUri, e);
                 } finally {
                     if (stream != null) {
                         try {
                             stream.close();
                         } catch (IOException e) {
-                            Log.w("ImageView", "Unable to close content: " + mUri, e);
+                            Log.w(LOG_TAG, "Unable to close content: " + mUri, e);
                         }
                     }
                 }
-        } else {
+            } else {
                 d = Drawable.createFromPath(mUri.toString());
             }
-    
+
             if (d == null) {
-                System.out.println("resolveUri failed on bad bitmap uri: " + mUri);
+                Log.w(LOG_TAG, "resolveUri failed on bad bitmap uri: " + mUri);
                 // Don't try again.
                 mUri = null;
             }
@@ -890,7 +888,7 @@
     }
 
     private void resizeFromDrawable() {
-        Drawable d = mDrawable;
+        final Drawable d = mDrawable;
         if (d != null) {
             int w = d.getIntrinsicWidth();
             if (w < 0) w = mDrawableWidth;
@@ -923,23 +921,23 @@
     private static Matrix.ScaleToFit scaleTypeToScaleToFit(ScaleType st)  {
         // ScaleToFit enum to their corresponding Matrix.ScaleToFit values
         return sS2FArray[st.nativeInt - 1];
-    }    
+    }
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         resolveUri();
         int w;
         int h;
-        
+
         // Desired aspect ratio of the view's contents (not including padding)
         float desiredAspect = 0.0f;
-        
+
         // We are allowed to change the view's width
         boolean resizeWidth = false;
-        
+
         // We are allowed to change the view's height
         boolean resizeHeight = false;
-        
+
         final int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
         final int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
 
@@ -959,15 +957,15 @@
             if (mAdjustViewBounds) {
                 resizeWidth = widthSpecMode != MeasureSpec.EXACTLY;
                 resizeHeight = heightSpecMode != MeasureSpec.EXACTLY;
-                
+
                 desiredAspect = (float) w / (float) h;
             }
         }
-        
-        int pleft = mPaddingLeft;
-        int pright = mPaddingRight;
-        int ptop = mPaddingTop;
-        int pbottom = mPaddingBottom;
+
+        final int pleft = mPaddingLeft;
+        final int pright = mPaddingRight;
+        final int ptop = mPaddingTop;
+        final int pbottom = mPaddingBottom;
 
         int widthSize;
         int heightSize;
@@ -975,7 +973,7 @@
         if (resizeWidth || resizeHeight) {
             /* If we get here, it means we want to resize to match the
                 drawables aspect ratio, and we have the freedom to change at
-                least one dimension. 
+                least one dimension.
             */
 
             // Get the max possible width given our constraints
@@ -986,13 +984,13 @@
 
             if (desiredAspect != 0.0f) {
                 // See what our actual aspect ratio is
-                float actualAspect = (float)(widthSize - pleft - pright) /
+                final float actualAspect = (float)(widthSize - pleft - pright) /
                                         (heightSize - ptop - pbottom);
-                
+
                 if (Math.abs(actualAspect - desiredAspect) > 0.0000001) {
-                    
+
                     boolean done = false;
-                    
+
                     // Try adjusting width to be proportional to height
                     if (resizeWidth) {
                         int newWidth = (int)(desiredAspect * (heightSize - ptop - pbottom)) +
@@ -1006,9 +1004,9 @@
                         if (newWidth <= widthSize) {
                             widthSize = newWidth;
                             done = true;
-                        } 
+                        }
                     }
-                    
+
                     // Try adjusting height to be proportional to width
                     if (!done && resizeHeight) {
                         int newHeight = (int)((widthSize - pleft - pright) / desiredAspect) +
@@ -1033,7 +1031,7 @@
             */
             w += pleft + pright;
             h += ptop + pbottom;
-                
+
             w = Math.max(w, getSuggestedMinimumWidth());
             h = Math.max(h, getSuggestedMinimumHeight());
 
@@ -1047,8 +1045,8 @@
     private int resolveAdjustedSize(int desiredSize, int maxSize,
                                    int measureSpec) {
         int result = desiredSize;
-        int specMode = MeasureSpec.getMode(measureSpec);
-        int specSize =  MeasureSpec.getSize(measureSpec);
+        final int specMode = MeasureSpec.getMode(measureSpec);
+        final int specSize =  MeasureSpec.getSize(measureSpec);
         switch (specMode) {
             case MeasureSpec.UNSPECIFIED:
                 /* Parent says we can be as big as we want. Just don't be larger
@@ -1057,8 +1055,8 @@
                 result = Math.min(desiredSize, maxSize);
                 break;
             case MeasureSpec.AT_MOST:
-                // Parent says we can be as big as we want, up to specSize. 
-                // Don't be larger than specSize, and don't be larger than 
+                // Parent says we can be as big as we want, up to specSize.
+                // Don't be larger than specSize, and don't be larger than
                 // the max size imposed on ourselves.
                 result = Math.min(Math.min(desiredSize, specSize), maxSize);
                 break;
@@ -1072,7 +1070,7 @@
 
     @Override
     protected boolean setFrame(int l, int t, int r, int b) {
-        boolean changed = super.setFrame(l, t, r, b);
+        final boolean changed = super.setFrame(l, t, r, b);
         mHaveFrame = true;
         configureBounds();
         return changed;
@@ -1083,14 +1081,14 @@
             return;
         }
 
-        int dwidth = mDrawableWidth;
-        int dheight = mDrawableHeight;
+        final int dwidth = mDrawableWidth;
+        final int dheight = mDrawableHeight;
 
-        int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
-        int vheight = getHeight() - mPaddingTop - mPaddingBottom;
+        final int vwidth = getWidth() - mPaddingLeft - mPaddingRight;
+        final int vheight = getHeight() - mPaddingTop - mPaddingBottom;
 
-        boolean fits = (dwidth < 0 || vwidth == dwidth) &&
-                       (dheight < 0 || vheight == dheight);
+        final boolean fits = (dwidth < 0 || vwidth == dwidth)
+                && (dheight < 0 || vheight == dheight);
 
         if (dwidth <= 0 || dheight <= 0 || ScaleType.FIT_XY == mScaleType) {
             /* If the drawable has no intrinsic size, or we're told to
@@ -1125,7 +1123,7 @@
                 float dx = 0, dy = 0;
 
                 if (dwidth * vheight > vwidth * dheight) {
-                    scale = (float) vheight / (float) dheight; 
+                    scale = (float) vheight / (float) dheight;
                     dx = (vwidth - dwidth * scale) * 0.5f;
                 } else {
                     scale = (float) vwidth / (float) dwidth;
@@ -1139,14 +1137,14 @@
                 float scale;
                 float dx;
                 float dy;
-                
+
                 if (dwidth <= vwidth && dheight <= vheight) {
                     scale = 1.0f;
                 } else {
                     scale = Math.min((float) vwidth / (float) dwidth,
                             (float) vheight / (float) dheight);
                 }
-                
+
                 dx = Math.round((vwidth - dwidth * scale) * 0.5f);
                 dy = Math.round((vheight - dheight * scale) * 0.5f);
 
@@ -1156,7 +1154,7 @@
                 // Generate the required transform.
                 mTempSrc.set(0, 0, dwidth, dheight);
                 mTempDst.set(0, 0, vwidth, vheight);
-                
+
                 mDrawMatrix = mMatrix;
                 mDrawMatrix.setRectToRect(mTempSrc, mTempDst, scaleTypeToScaleToFit(mScaleType));
             }
@@ -1166,7 +1164,8 @@
     @Override
     protected void drawableStateChanged() {
         super.drawableStateChanged();
-        Drawable d = mDrawable;
+
+        final Drawable d = mDrawable;
         if (d != null && d.isStateful()) {
             d.setState(getDrawableState());
         }
@@ -1213,9 +1212,9 @@
         if (mDrawMatrix == null && mPaddingTop == 0 && mPaddingLeft == 0) {
             mDrawable.draw(canvas);
         } else {
-            int saveCount = canvas.getSaveCount();
+            final int saveCount = canvas.getSaveCount();
             canvas.save();
-            
+
             if (mCropToPadding) {
                 final int scrollX = mScrollX;
                 final int scrollY = mScrollY;
@@ -1223,7 +1222,7 @@
                         scrollX + mRight - mLeft - mPaddingRight,
                         scrollY + mBottom - mTop - mPaddingBottom);
             }
-            
+
             canvas.translate(mPaddingLeft, mPaddingTop);
 
             if (mDrawMatrix != null) {
@@ -1258,7 +1257,7 @@
      *
      * @param baseline The baseline to use, or -1 if none is to be provided.
      *
-     * @see #setBaseline(int) 
+     * @see #setBaseline(int)
      * @attr ref android.R.styleable#ImageView_baseline
      */
     public void setBaseline(int baseline) {
@@ -1295,11 +1294,11 @@
 
     /**
      * Set a tinting option for the image.
-     * 
+     *
      * @param color Color tint to apply.
      * @param mode How to apply the color.  The standard mode is
      * {@link PorterDuff.Mode#SRC_ATOP}
-     * 
+     *
      * @attr ref android.R.styleable#ImageView_tint
      */
     public final void setColorFilter(int color, PorterDuff.Mode mode) {
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index b5e08ca..ad939be 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -25,6 +25,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
+import android.os.Build;
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.View;
@@ -99,6 +100,13 @@
     public static final int SHOW_DIVIDER_END = 4;
 
     /**
+     * Compatibility check. Old versions of the platform would give different
+     * results from measurement passes using EXACTLY and non-EXACTLY modes,
+     * even when the resulting size was the same.
+     */
+    private final boolean mAllowInconsistentMeasurement;
+
+    /**
      * Whether the children of this layout are baseline aligned.  Only applicable
      * if {@link #mOrientation} is horizontal.
      */
@@ -231,6 +239,9 @@
         mShowDividers = a.getInt(R.styleable.LinearLayout_showDividers, SHOW_DIVIDER_NONE);
         mDividerPadding = a.getDimensionPixelSize(R.styleable.LinearLayout_dividerPadding, 0);
 
+        final int version = context.getApplicationInfo().targetSdkVersion;
+        mAllowInconsistentMeasurement = version <= Build.VERSION_CODES.M;
+
         a.recycle();
     }
 
@@ -699,6 +710,7 @@
         final boolean useLargestChild = mUseLargestChild;
 
         int largestChildHeight = Integer.MIN_VALUE;
+        int consumedExcessSpace = 0;
 
         // See how tall everyone is. Also remember max width.
         for (int i = 0; i < count; ++i) {
@@ -718,26 +730,25 @@
                 mTotalLength += mDividerHeight;
             }
 
-            LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
 
             totalWeight += lp.weight;
-            
-            if (heightMode == MeasureSpec.EXACTLY && lp.height == 0 && lp.weight > 0) {
-                // Optimization: don't bother measuring children who are going to use
-                // leftover space. These views will get measured again down below if
-                // there is any leftover space.
+
+            final boolean useExcessSpace = lp.height == 0 && lp.weight > 0;
+            if (heightMode == MeasureSpec.EXACTLY && useExcessSpace) {
+                // Optimization: don't bother measuring children who are only
+                // laid out using excess space. These views will get measured
+                // later if we have space to distribute.
                 final int totalLength = mTotalLength;
                 mTotalLength = Math.max(totalLength, totalLength + lp.topMargin + lp.bottomMargin);
                 skippedMeasure = true;
             } else {
-                int oldHeight = Integer.MIN_VALUE;
-
-                if (lp.height == 0 && lp.weight > 0) {
-                    // heightMode is either UNSPECIFIED or AT_MOST, and this
-                    // child wanted to stretch to fill available space.
-                    // Translate that to WRAP_CONTENT so that it does not end up
-                    // with a height of 0
-                    oldHeight = 0;
+                if (useExcessSpace) {
+                    // The heightMode is either UNSPECIFIED or AT_MOST, and
+                    // this child is only laid out using excess space. Measure
+                    // using WRAP_CONTENT so that we can find out the view's
+                    // optimal height. We'll restore the original height of 0
+                    // after measurement.
                     lp.height = LayoutParams.WRAP_CONTENT;
                 }
 
@@ -745,15 +756,19 @@
                 // previous children have given a weight, then we allow it to
                 // use all available space (and we will shrink things later
                 // if needed).
-                measureChildBeforeLayout(
-                       child, i, widthMeasureSpec, 0, heightMeasureSpec,
-                       totalWeight == 0 ? mTotalLength : 0);
-
-                if (oldHeight != Integer.MIN_VALUE) {
-                   lp.height = oldHeight;
-                }
+                final int usedHeight = totalWeight == 0 ? mTotalLength : 0;
+                measureChildBeforeLayout(child, i, widthMeasureSpec, 0,
+                        heightMeasureSpec, usedHeight);
 
                 final int childHeight = child.getMeasuredHeight();
+                if (useExcessSpace) {
+                    // Restore the original height and record how much space
+                    // we've allocated to excess-only children so that we can
+                    // match the behavior of EXACTLY measurement.
+                    lp.height = 0;
+                    consumedExcessSpace += childHeight;
+                }
+
                 final int totalLength = mTotalLength;
                 mTotalLength = Math.max(totalLength, totalLength + childHeight + lp.topMargin +
                        lp.bottomMargin + getNextLocationOffset(child));
@@ -857,52 +872,42 @@
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
         // measurement on any children, we need to measure them now.
-        int delta = heightSize - mTotalLength;
+        final int delta = heightSize - mTotalLength
+                + (mAllowInconsistentMeasurement ? 0 : consumedExcessSpace);
         if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
-            float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+            final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
 
             mTotalLength = 0;
 
             for (int i = 0; i < count; ++i) {
                 final View child = getVirtualChildAt(i);
-                
-                if (child.getVisibility() == View.GONE) {
+                if (child == null || child.getVisibility() == View.GONE) {
                     continue;
                 }
-                
-                LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams) child.getLayoutParams();
-                
-                float childExtra = lp.weight;
+
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final float childExtra = lp.weight;
                 if (childExtra > 0) {
-                    // Child said it could absorb extra space -- give him his share
-                    int share = (int) (childExtra * delta / weightSum);
-                    weightSum -= childExtra;
-                    delta -= share;
-
-                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
-                            mPaddingLeft + mPaddingRight +
-                                    lp.leftMargin + lp.rightMargin, lp.width);
-
-                    // TODO: Use a field like lp.isMeasured to figure out if this
-                    // child has been previously measured
-                    if ((lp.height != 0) || (heightMode != MeasureSpec.EXACTLY)) {
-                        // child was measured once already above...
-                        // base new measurement on stored values
-                        int childHeight = child.getMeasuredHeight() + share;
-                        if (childHeight < 0) {
-                            childHeight = 0;
-                        }
-                        
-                        child.measure(childWidthMeasureSpec,
-                                MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY));
+                    final int share = (int) (childExtra * delta / weightSum);
+                    final int childHeight;
+                    if (lp.height == 0 && (!mAllowInconsistentMeasurement
+                            || heightMode == MeasureSpec.EXACTLY)) {
+                        // This child needs to be laid out from scratch using
+                        // only its share of excess space.
+                        childHeight = share;
                     } else {
-                        // child was skipped in the loop above.
-                        // Measure for this first time here      
-                        child.measure(childWidthMeasureSpec,
-                                MeasureSpec.makeMeasureSpec(share > 0 ? share : 0,
-                                        MeasureSpec.EXACTLY));
+                        // This child had some intrinsic height to which we
+                        // need to add its share of excess space.
+                        childHeight = child.getMeasuredHeight() + share;
                     }
 
+                    final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            Math.max(0, childHeight), MeasureSpec.EXACTLY);
+                    final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
+                            mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
+                            lp.width);
+                    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
+
                     // Child may now not fit in vertical dimension.
                     childState = combineMeasuredStates(childState, child.getMeasuredState()
                             & (MEASURED_STATE_MASK>>MEASURED_HEIGHT_STATE_SHIFT));
@@ -1043,6 +1048,7 @@
         final boolean isExactly = widthMode == MeasureSpec.EXACTLY;
 
         int largestChildWidth = Integer.MIN_VALUE;
+        int usedExcessSpace = 0;
 
         // See how wide everyone is. Also remember max height.
         for (int i = 0; i < count; ++i) {
@@ -1062,15 +1068,15 @@
                 mTotalLength += mDividerWidth;
             }
 
-            final LinearLayout.LayoutParams lp = (LinearLayout.LayoutParams)
-                    child.getLayoutParams();
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
 
             totalWeight += lp.weight;
-            
-            if (widthMode == MeasureSpec.EXACTLY && lp.width == 0 && lp.weight > 0) {
-                // Optimization: don't bother measuring children who are going to use
-                // leftover space. These views will get measured again down below if
-                // there is any leftover space.
+
+            final boolean useExcessSpace = lp.width == 0 && lp.weight > 0;
+            if (widthMode == MeasureSpec.EXACTLY && useExcessSpace) {
+                // Optimization: don't bother measuring children who are only
+                // laid out using excess space. These views will get measured
+                // later if we have space to distribute.
                 if (isExactly) {
                     mTotalLength += lp.leftMargin + lp.rightMargin;
                 } else {
@@ -1094,14 +1100,12 @@
                     skippedMeasure = true;
                 }
             } else {
-                int oldWidth = Integer.MIN_VALUE;
-
-                if (lp.width == 0 && lp.weight > 0) {
-                    // widthMode is either UNSPECIFIED or AT_MOST, and this
-                    // child
-                    // wanted to stretch to fill available space. Translate that to
-                    // WRAP_CONTENT so that it does not end up with a width of 0
-                    oldWidth = 0;
+                if (useExcessSpace) {
+                    // The widthMode is either UNSPECIFIED or AT_MOST, and
+                    // this child is only laid out using excess space. Measure
+                    // using WRAP_CONTENT so that we can find out the view's
+                    // optimal width. We'll restore the original width of 0
+                    // after measurement.
                     lp.width = LayoutParams.WRAP_CONTENT;
                 }
 
@@ -1109,22 +1113,26 @@
                 // previous children have given a weight, then we allow it to
                 // use all available space (and we will shrink things later
                 // if needed).
-                measureChildBeforeLayout(child, i, widthMeasureSpec,
-                        totalWeight == 0 ? mTotalLength : 0,
+                final int usedWidth = totalWeight == 0 ? mTotalLength : 0;
+                measureChildBeforeLayout(child, i, widthMeasureSpec, usedWidth,
                         heightMeasureSpec, 0);
 
-                if (oldWidth != Integer.MIN_VALUE) {
-                    lp.width = oldWidth;
+                final int childWidth = child.getMeasuredWidth();
+                if (useExcessSpace) {
+                    // Restore the original width and record how much space
+                    // we've allocated to excess-only children so that we can
+                    // match the behavior of EXACTLY measurement.
+                    lp.width = 0;
+                    usedExcessSpace += childWidth;
                 }
 
-                final int childWidth = child.getMeasuredWidth();
                 if (isExactly) {
-                    mTotalLength += childWidth + lp.leftMargin + lp.rightMargin +
-                            getNextLocationOffset(child);
+                    mTotalLength += childWidth + lp.leftMargin + lp.rightMargin
+                            + getNextLocationOffset(child);
                 } else {
                     final int totalLength = mTotalLength;
-                    mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin +
-                           lp.rightMargin + getNextLocationOffset(child));
+                    mTotalLength = Math.max(totalLength, totalLength + childWidth + lp.leftMargin
+                            + lp.rightMargin + getNextLocationOffset(child));
                 }
 
                 if (useLargestChild) {
@@ -1242,9 +1250,10 @@
         // Either expand children with weight to take up available space or
         // shrink them if they extend beyond our current bounds. If we skipped
         // measurement on any children, we need to measure them now.
-        int delta = widthSize - mTotalLength;
+        final int delta = widthSize - mTotalLength
+                + (mAllowInconsistentMeasurement ? 0 : usedExcessSpace);
         if (skippedMeasure || delta != 0 && totalWeight > 0.0f) {
-            float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
+            final float weightSum = mWeightSum > 0.0f ? mWeightSum : totalWeight;
 
             maxAscent[0] = maxAscent[1] = maxAscent[2] = maxAscent[3] = -1;
             maxDescent[0] = maxDescent[1] = maxDescent[2] = maxDescent[3] = -1;
@@ -1254,45 +1263,32 @@
 
             for (int i = 0; i < count; ++i) {
                 final View child = getVirtualChildAt(i);
-
                 if (child == null || child.getVisibility() == View.GONE) {
                     continue;
                 }
-                
-                final LinearLayout.LayoutParams lp =
-                        (LinearLayout.LayoutParams) child.getLayoutParams();
 
-                float childExtra = lp.weight;
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                final float childExtra = lp.weight;
                 if (childExtra > 0) {
-                    // Child said it could absorb extra space -- give him his share
-                    int share = (int) (childExtra * delta / weightSum);
-                    weightSum -= childExtra;
-                    delta -= share;
+                    final int share = (int) (childExtra * delta / weightSum);
+                    final int childWidth;
+                    if (lp.width == 0 && (!mAllowInconsistentMeasurement
+                            || widthMode == MeasureSpec.EXACTLY)) {
+                        // This child needs to be laid out from scratch using
+                        // only its share of excess space.
+                        childWidth = share;
+                    } else {
+                        // This child had some intrinsic width to which we
+                        // need to add its share of excess space.
+                        childWidth = child.getMeasuredWidth() + share;
+                    }
 
-                    final int childHeightMeasureSpec = getChildMeasureSpec(
-                            heightMeasureSpec,
+                    final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(
+                            Math.max(0, childWidth), MeasureSpec.EXACTLY);
+                    final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
                             mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin,
                             lp.height);
-
-                    // TODO: Use a field like lp.isMeasured to figure out if this
-                    // child has been previously measured
-                    if ((lp.width != 0) || (widthMode != MeasureSpec.EXACTLY)) {
-                        // child was measured once already above ... base new measurement
-                        // on stored values
-                        int childWidth = child.getMeasuredWidth() + share;
-                        if (childWidth < 0) {
-                            childWidth = 0;
-                        }
-
-                        child.measure(
-                            MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
-                            childHeightMeasureSpec);
-                    } else {
-                        // child was skipped in the loop above. Measure for this first time here
-                        child.measure(MeasureSpec.makeMeasureSpec(
-                                share > 0 ? share : 0, MeasureSpec.EXACTLY),
-                                childHeightMeasureSpec);
-                    }
+                    child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
 
                     // Child may now not fit in horizontal dimension.
                     childState = combineMeasuredStates(childState,
diff --git a/core/java/android/widget/SearchView.java b/core/java/android/widget/SearchView.java
index 088adbb..ad2b4a7 100644
--- a/core/java/android/widget/SearchView.java
+++ b/core/java/android/widget/SearchView.java
@@ -816,7 +816,15 @@
         mSearchButton.setVisibility(visCollapsed);
         updateSubmitButton(hasText);
         mSearchEditFrame.setVisibility(collapsed ? GONE : VISIBLE);
-        mCollapsedIcon.setVisibility(mIconifiedByDefault ? GONE : VISIBLE);
+
+        final int iconVisibility;
+        if (mCollapsedIcon.getDrawable() == null || mIconifiedByDefault) {
+            iconVisibility = GONE;
+        } else {
+            iconVisibility = VISIBLE;
+        }
+        mCollapsedIcon.setVisibility(iconVisibility);
+
         updateCloseButton();
         updateVoiceButton(!hasText);
         updateSubmitArea();
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/TextView.java b/core/java/android/widget/TextView.java
index ce66eeb..7a64377 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -139,6 +139,7 @@
 import android.view.textservice.TextServicesManager;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastMath;
 import com.android.internal.widget.EditableInputConnection;
 
@@ -1695,6 +1696,15 @@
         throw new UnsupportedOperationException("not implemented");
     }
 
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public final Editor getEditorForTesting() {
+        return mEditor;
+    }
+
     /**
      * Associate an {@link android.content.UndoManager} with this TextView.  Once
      * done, all edit operations on the TextView will result in appropriate
@@ -8755,12 +8765,9 @@
     public void onPopulateAccessibilityEventInternal(AccessibilityEvent event) {
         super.onPopulateAccessibilityEventInternal(event);
 
-        final boolean isPassword = hasPasswordTransformationMethod();
-        if (!isPassword || shouldSpeakPasswordsForAccessibility()) {
-            final CharSequence text = getTextForAccessibility();
-            if (!TextUtils.isEmpty(text)) {
-                event.getText().add(text);
-            }
+        final CharSequence text = getTextForAccessibility();
+        if (!TextUtils.isEmpty(text)) {
+            event.getText().add(text);
         }
     }
 
@@ -8911,10 +8918,7 @@
 
         final boolean isPassword = hasPasswordTransformationMethod();
         info.setPassword(isPassword);
-
-        if (!isPassword || shouldSpeakPasswordsForAccessibility()) {
-            info.setText(getTextForAccessibility());
-        }
+        info.setText(getTextForAccessibility());
 
         if (mBufferType == BufferType.EDITABLE) {
             info.setEditable(true);
@@ -9146,18 +9150,30 @@
     }
 
     /**
-     * Gets the text reported for accessibility purposes.
+     * Returns the text that should be exposed to accessibility services.
+     * <p>
+     * This approximates what is displayed visually. If the user has specified
+     * that accessibility services should speak passwords, this method will
+     * bypass any password transformation method and return unobscured text.
      *
-     * @return The accessibility text.
-     *
-     * @hide
+     * @return the text that should be exposed to accessibility services, may
+     *         be {@code null} if no text is set
      */
-    public CharSequence getTextForAccessibility() {
-        CharSequence text = getText();
-        if (TextUtils.isEmpty(text)) {
-            text = getHint();
+    @Nullable
+    private CharSequence getTextForAccessibility() {
+        // If the text is empty, we must be showing the hint text.
+        if (TextUtils.isEmpty(mText)) {
+            return mHint;
         }
-        return text;
+
+        // Check whether we need to bypass the transformation
+        // method and expose unobscured text.
+        if (hasPasswordTransformationMethod() && shouldSpeakPasswordsForAccessibility()) {
+            return mText;
+        }
+
+        // Otherwise, speak whatever text is being displayed.
+        return mTransformed;
     }
 
     void sendAccessibilityEventTypeViewTextChanged(CharSequence beforeText,
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index c1b184e..9d12803 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -23,6 +23,7 @@
 import android.content.res.Configuration;
 import android.graphics.drawable.Drawable;
 import android.view.ActionMode;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.Menu;
@@ -467,6 +468,9 @@
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
         Menu menu = mDecorToolbar.getMenu();
         if (menu != null) {
+            final KeyCharacterMap kmap = KeyCharacterMap.load(
+                    event != null ? event.getDeviceId() : KeyCharacterMap.VIRTUAL_KEYBOARD);
+            menu.setQwertyMode(kmap.getKeyboardType() != KeyCharacterMap.NUMERIC);
             menu.performShortcut(keyCode, event, 0);
         }
         // This action bar always returns true for handling keyboard shortcuts.
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index be26c24..55e23b1 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -20,6 +20,7 @@
 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.app.ActivityManager.INVALID_STACK_ID;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -5250,7 +5251,7 @@
      * @return Returns the workspace stack id which contains this window.
      **/
     private int getWorkspaceId() {
-        int workspaceId = FULLSCREEN_WORKSPACE_STACK_ID;
+        int workspaceId = INVALID_STACK_ID;
         WindowControllerCallback callback = getWindowControllerCallback();
         if (callback != null) {
             try {
@@ -5259,6 +5260,9 @@
                 Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
             }
         }
+        if (workspaceId == INVALID_STACK_ID) {
+            return FULLSCREEN_WORKSPACE_STACK_ID;
+        }
         return workspaceId;
     }
 
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 1e41e63..ab3ec98 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -71,5 +71,10 @@
 
     void showAssistDisclosure();
     void startAssist(in Bundle args);
+
+    /**
+     * Notifies the status bar that a camera launch gesture has been detected.
+     */
+    void onCameraLaunchGestureDetected();
 }
 
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index 229407e..6816646 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -29,6 +29,7 @@
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.HashMap;
 import java.util.Vector;
 
@@ -1864,6 +1865,20 @@
     }
 
     /**
+     * Removes a message from the deferred messages queue.
+     */
+    protected final void removeDeferredMessages(int what) {
+        SmHandler smh = mSmHandler;
+        if (smh == null) return;
+
+        Iterator<Message> iterator = smh.mDeferredMessages.iterator();
+        while (iterator.hasNext()) {
+            Message msg = iterator.next();
+            if (msg.what == what) iterator.remove();
+        }
+    }
+
+    /**
      * Validate that the message was sent by
      * {@link StateMachine#quit} or {@link StateMachine#quitNow}.
      * */
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index dfb7c50..4e4552d 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.widget;
 
+import android.app.trust.IStrongAuthTracker;
 import com.android.internal.widget.VerifyCredentialResponse;
 
 /** {@hide} */
@@ -35,4 +36,7 @@
     boolean checkVoldPassword(int userId);
     boolean havePattern(int userId);
     boolean havePassword(int userId);
+    void registerStrongAuthTracker(in IStrongAuthTracker tracker);
+    void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
+    void requireStrongAuth(int strongAuthReason, int userId);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index ca184d1..073a2ad 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -16,19 +16,19 @@
 
 package com.android.internal.widget;
 
-import android.Manifest;
+import android.annotation.IntDef;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.admin.DevicePolicyManager;
+import android.app.trust.IStrongAuthTracker;
 import android.app.trust.TrustManager;
-import android.bluetooth.BluetoothClass;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.pm.PackageManager;
 import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -39,9 +39,12 @@
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.SparseIntArray;
 
 import com.google.android.collect.Lists;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -229,7 +232,7 @@
     public void reportFailedPasswordAttempt(int userId) {
         getDevicePolicyManager().reportFailedPasswordAttempt(userId);
         getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
-        getTrustManager().reportRequireCredentialEntry(userId);
+        requireCredentialEntry(userId);
     }
 
     public void reportSuccessfulPasswordAttempt(int userId) {
@@ -453,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);
         }
@@ -513,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();
@@ -535,7 +538,7 @@
     }
 
     private void updateCryptoUserInfo(int userId) {
-        if (userId != UserHandle.USER_OWNER) {
+        if (userId != UserHandle.USER_SYSTEM) {
             return;
         }
 
@@ -711,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();
@@ -1005,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;
         }
 
@@ -1028,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;
         }
 
@@ -1168,10 +1171,32 @@
     }
 
     /**
-     * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
+     * Disable trust until credentials have been entered for user {@param userId}.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     *
+     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
      */
     public void requireCredentialEntry(int userId) {
-        getTrustManager().reportRequireCredentialEntry(userId);
+        requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+    }
+
+    /**
+     * Requests strong authentication for user {@param userId}.
+     *
+     * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+     *
+     * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
+     *                         the reason for and the strength of the requested authentication.
+     * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
+     */
+    public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
+            int userId) {
+        try {
+            getLockSettings().requireStrongAuth(strongAuthReason, userId);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error while requesting strong auth: " + e);
+        }
     }
 
     private void onAfterChangingPassword(int userHandle) {
@@ -1185,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;
         }
@@ -1209,4 +1234,153 @@
             throw new IllegalStateException("should not be called from the main thread.");
         }
     }
+
+    public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+        try {
+            getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Could not register StrongAuthTracker");
+        }
+    }
+
+    public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+        try {
+            getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
+        } catch (RemoteException e) {
+            Log.e(TAG, "Could not unregister StrongAuthTracker", e);
+        }
+    }
+
+    /**
+     * Tracks the global strong authentication state.
+     */
+    public static class StrongAuthTracker {
+
+        @IntDef(flag = true,
+                value = { STRONG_AUTH_NOT_REQUIRED,
+                        STRONG_AUTH_REQUIRED_AFTER_BOOT,
+                        STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+                        SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface StrongAuthFlags {}
+
+        /**
+         * Strong authentication is not required.
+         */
+        public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
+
+        /**
+         * Strong authentication is required because the user has not authenticated since boot.
+         */
+        public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
+
+        /**
+         * Strong authentication is required because a device admin has 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.
+         */
+        public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+
+        /**
+         * Strong authentication is required because the user has been locked out after too many
+         * attempts.
+         */
+        public static final int STRONG_AUTH_REQUIRED_AFTER_LOCKOUT = 0x8;
+
+        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 final H mHandler;
+
+        public StrongAuthTracker() {
+            this(Looper.myLooper());
+        }
+
+        /**
+         * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
+         *               will be scheduled.
+         */
+        public StrongAuthTracker(Looper looper) {
+            mHandler = new H(looper);
+        }
+
+        /**
+         * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
+         * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
+         * authentication is required.
+         *
+         * @param userId the user for whom the state is queried.
+         */
+        public @StrongAuthFlags int getStrongAuthForUser(int userId) {
+            return mStrongAuthRequiredForUser.get(userId, DEFAULT);
+        }
+
+        /**
+         * @return true if unlocking with trust alone is allowed for {@param userId} by the current
+         * strong authentication requirements.
+         */
+        public boolean isTrustAllowedForUser(int userId) {
+            return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
+        }
+
+        /**
+         * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
+         * current strong authentication requirements.
+         */
+        public boolean isFingerprintAllowedForUser(int userId) {
+            return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+        }
+
+        /**
+         * Called when the strong authentication requirements for {@param userId} changed.
+         */
+        public void onStrongAuthRequiredChanged(int userId) {
+        }
+
+        void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+                int userId) {
+
+            int oldValue = getStrongAuthForUser(userId);
+            if (strongAuthFlags != oldValue) {
+                if (strongAuthFlags == DEFAULT) {
+                    mStrongAuthRequiredForUser.delete(userId);
+                } else {
+                    mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
+                }
+                onStrongAuthRequiredChanged(userId);
+            }
+        }
+
+
+        final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
+            @Override
+            public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+                    int userId) {
+                mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
+                        strongAuthFlags, userId).sendToTarget();
+            }
+        };
+
+        private class H extends Handler {
+            static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
+
+            public H(Looper looper) {
+                super(looper);
+            }
+
+            @Override
+            public void handleMessage(Message msg) {
+                switch (msg.what) {
+                    case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
+                        handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
+                        break;
+                }
+            }
+        };
+    }
 }
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 92812f8..491b323 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -124,6 +124,12 @@
         // input device we are listening to.
         switch (e.getActionMasked()) {
             case MotionEvent.ACTION_DOWN:
+                if (!mShowDecor) {
+                    // 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 &&
@@ -342,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/android/graphics/HarfBuzzNGFaceSkia.cpp b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
index e537942..ae99f0b 100644
--- a/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
+++ b/core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp
@@ -32,6 +32,7 @@
 
 #include "HarfBuzzNGFaceSkia.h"
 
+#include <stdlib.h>
 #include <cutils/log.h>
 #include <SkPaint.h>
 #include <SkPath.h>
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index f7b5dc2..dbd7c89 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -519,6 +519,9 @@
 
 int register_android_graphics_Path(JNIEnv* env) {
     return RegisterMethodsOrDie(env, "android/graphics/Path", methods, NELEM(methods));
+
+    static_assert(0  == SkPath::kCW_Direction,  "direction_mismatch");
+    static_assert(1  == SkPath::kCCW_Direction, "direction_mismatch");
 }
 
 }
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_media_AudioErrors.h b/core/jni/android_media_AudioErrors.h
index 4907830..c17a020 100644
--- a/core/jni/android_media_AudioErrors.h
+++ b/core/jni/android_media_AudioErrors.h
@@ -32,6 +32,7 @@
     AUDIO_JAVA_PERMISSION_DENIED  = -4,
     AUDIO_JAVA_NO_INIT            = -5,
     AUDIO_JAVA_DEAD_OBJECT        = -6,
+    AUDIO_JAVA_WOULD_BLOCK        = -7,
 };
 
 static inline jint nativeToJavaStatus(status_t status) {
@@ -46,6 +47,8 @@
         return AUDIO_JAVA_PERMISSION_DENIED;
     case NO_INIT:
         return AUDIO_JAVA_NO_INIT;
+    case WOULD_BLOCK:
+        return AUDIO_JAVA_WOULD_BLOCK;
     case DEAD_OBJECT:
         return AUDIO_JAVA_DEAD_OBJECT;
     default:
diff --git a/core/jni/android_view_DisplayListCanvas.cpp b/core/jni/android_view_DisplayListCanvas.cpp
index 3833325..460c1a1 100644
--- a/core/jni/android_view_DisplayListCanvas.cpp
+++ b/core/jni/android_view_DisplayListCanvas.cpp
@@ -40,18 +40,14 @@
 
 using namespace uirenderer;
 
-static struct {
-    jmethodID set;
-} gRectClassInfo;
-
 // ----------------------------------------------------------------------------
 // Setup
 // ----------------------------------------------------------------------------
 
 static void android_view_DisplayListCanvas_insertReorderBarrier(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jboolean reorderEnable) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
-    renderer->insertReorderBarrier(reorderEnable);
+        jlong canvasPtr, jboolean reorderEnable) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas->insertReorderBarrier(reorderEnable);
 }
 
 // ----------------------------------------------------------------------------
@@ -59,10 +55,10 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_DisplayListCanvas_callDrawGLFunction(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong functorPtr) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+        jlong canvasPtr, jlong functorPtr) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
-    renderer->callDrawGLFunction(functor);
+    canvas->callDrawGLFunction(functor);
 }
 
 // ----------------------------------------------------------------------------
@@ -82,9 +78,9 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_DisplayListCanvas_drawRoundRectProps(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
+        jlong canvasPtr, jlong leftPropPtr, jlong topPropPtr, jlong rightPropPtr,
         jlong bottomPropPtr, jlong rxPropPtr, jlong ryPropPtr, jlong paintPropPtr) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
     CanvasPropertyPrimitive* leftProp = reinterpret_cast<CanvasPropertyPrimitive*>(leftPropPtr);
     CanvasPropertyPrimitive* topProp = reinterpret_cast<CanvasPropertyPrimitive*>(topPropPtr);
     CanvasPropertyPrimitive* rightProp = reinterpret_cast<CanvasPropertyPrimitive*>(rightPropPtr);
@@ -92,17 +88,17 @@
     CanvasPropertyPrimitive* rxProp = reinterpret_cast<CanvasPropertyPrimitive*>(rxPropPtr);
     CanvasPropertyPrimitive* ryProp = reinterpret_cast<CanvasPropertyPrimitive*>(ryPropPtr);
     CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
-    renderer->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
+    canvas->drawRoundRect(leftProp, topProp, rightProp, bottomProp, rxProp, ryProp, paintProp);
 }
 
 static void android_view_DisplayListCanvas_drawCircleProps(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+        jlong canvasPtr, jlong xPropPtr, jlong yPropPtr, jlong radiusPropPtr, jlong paintPropPtr) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
     CanvasPropertyPrimitive* xProp = reinterpret_cast<CanvasPropertyPrimitive*>(xPropPtr);
     CanvasPropertyPrimitive* yProp = reinterpret_cast<CanvasPropertyPrimitive*>(yPropPtr);
     CanvasPropertyPrimitive* radiusProp = reinterpret_cast<CanvasPropertyPrimitive*>(radiusPropPtr);
     CanvasPropertyPaint* paintProp = reinterpret_cast<CanvasPropertyPaint*>(paintPropPtr);
-    renderer->drawCircle(xProp, yProp, radiusProp, paintProp);
+    canvas->drawCircle(xProp, yProp, radiusProp, paintProp);
 }
 
 // ----------------------------------------------------------------------------
@@ -110,9 +106,9 @@
 // ----------------------------------------------------------------------------
 
 static jlong android_view_DisplayListCanvas_finishRecording(JNIEnv* env,
-        jobject clazz, jlong rendererPtr) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
-    return reinterpret_cast<jlong>(renderer->finishRecording());
+        jobject clazz, jlong canvasPtr) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    return reinterpret_cast<jlong>(canvas->finishRecording());
 }
 
 static jlong android_view_DisplayListCanvas_createDisplayListCanvas(JNIEnv* env, jobject clazz,
@@ -121,17 +117,17 @@
 }
 
 static void android_view_DisplayListCanvas_resetDisplayListCanvas(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jint width, jint height) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
-    renderer->reset(width, height);
+        jlong canvasPtr, jint width, jint height) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
+    canvas->reset(width, height);
 }
 
 
 static void android_view_DisplayListCanvas_drawRenderNode(JNIEnv* env,
-        jobject clazz, jlong rendererPtr, jlong renderNodePtr) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+        jobject clazz, jlong canvasPtr, jlong renderNodePtr) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
     RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
-    renderer->drawRenderNode(renderNode);
+    canvas->drawRenderNode(renderNode);
 }
 
 // ----------------------------------------------------------------------------
@@ -139,10 +135,10 @@
 // ----------------------------------------------------------------------------
 
 static void android_view_DisplayListCanvas_drawLayer(JNIEnv* env, jobject clazz,
-        jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
-    DisplayListCanvas* renderer = reinterpret_cast<DisplayListCanvas*>(rendererPtr);
+        jlong canvasPtr, jlong layerPtr) {
+    DisplayListCanvas* canvas = reinterpret_cast<DisplayListCanvas*>(canvasPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
-    renderer->drawLayer(layer, x, y);
+    canvas->drawLayer(layer);
 }
 
 // ----------------------------------------------------------------------------
@@ -192,7 +188,7 @@
     { "nCreateDisplayListCanvas", "(II)J",     (void*) android_view_DisplayListCanvas_createDisplayListCanvas },
     { "nResetDisplayListCanvas", "(JII)V",     (void*) android_view_DisplayListCanvas_resetDisplayListCanvas },
 
-    { "nDrawLayer",               "(JJFF)V",   (void*) android_view_DisplayListCanvas_drawLayer },
+    { "nDrawLayer",               "(JJ)V",     (void*) android_view_DisplayListCanvas_drawLayer },
 
     { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureWidth },
     { "nGetMaximumTextureHeight", "()I",       (void*) android_view_DisplayListCanvas_getMaxTextureHeight },
@@ -204,9 +200,6 @@
 };
 
 int register_android_view_DisplayListCanvas(JNIEnv* env) {
-    jclass clazz = FindClassOrDie(env, "android/graphics/Rect");
-    gRectClassInfo.set = GetMethodIDOrDie(env, clazz, "set", "(IIII)V");
-
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index aa79d70..17d2a5e 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -158,7 +158,7 @@
 
     sp<GraphicBuffer> buffer(wrapper->buffer);
 
-    Rect rect;
+    Rect rect(Rect::EMPTY_RECT);
     if (dirtyRect) {
         rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
         rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 9e49afb..36ba892 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -79,12 +79,6 @@
     layer->updateTexImage();
 }
 
-static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
-        jlong layerUpdaterPtr) {
-    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
-    return layer->backingLayer()->getTextureId();
-}
-
 // ----------------------------------------------------------------------------
 // JNI Glue
 // ----------------------------------------------------------------------------
@@ -98,8 +92,6 @@
     { "nSetSurfaceTexture",      "(JLandroid/graphics/SurfaceTexture;Z)V",
             (void*) android_view_HardwareLayer_setSurfaceTexture },
     { "nUpdateSurfaceTexture",   "(J)V",       (void*) android_view_HardwareLayer_updateSurfaceTexture },
-
-    { "nGetTexName",             "(J)I",       (void*) android_view_HardwareLayer_getTexName },
 };
 
 int register_android_view_HardwareLayer(JNIEnv* env) {
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index abd2409..4a311d31 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -292,7 +292,7 @@
         return 0;
     }
 
-    Rect dirtyRect;
+    Rect dirtyRect(Rect::EMPTY_RECT);
     Rect* dirtyRectPtr = NULL;
 
     if (dirtyRectObj) {
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 7e05793..beb83b1 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -142,7 +142,7 @@
 
     ANativeWindow_Buffer buffer;
 
-    Rect rect;
+    Rect rect(Rect::EMPTY_RECT);
     if (dirtyRect) {
         rect.left = GET_INT(dirtyRect, gRectClassInfo.left);
         rect.top = GET_INT(dirtyRect, gRectClassInfo.top);
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2fcce67..b0621e9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -786,6 +786,46 @@
         android:protectionLevel="normal"
         android:permissionFlags="hidden"/>
 
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.WRITE_SMS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.MANAGE_ACCOUNTS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.USE_CREDENTIALS"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
     <!-- ====================================================================== -->
     <!-- INSTALL PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
@@ -2527,10 +2567,11 @@
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Must be required by a {@link
+    <!-- Must be required by a {@link
          android.service.notification.ConditionProviderService},
          to ensure that only the system can bind to it.
-         @hide -->
+         <p>Protection level: signature
+         -->
     <permission android:name="android.permission.BIND_CONDITION_PROVIDER_SERVICE"
         android:protectionLevel="signature" />
 
@@ -2764,7 +2805,7 @@
         </activity>
 
         <receiver android:name="com.android.server.BootReceiver"
-                android:primaryUserOnly="true">
+                android:systemUserOnly="true">
             <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
diff --git a/core/res/res/drawable-hdpi/sim_dark_blue.9.png b/core/res/res/drawable-hdpi/sim_dark_blue.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_green.9.png b/core/res/res/drawable-hdpi/sim_dark_green.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_orange.9.png b/core/res/res/drawable-hdpi/sim_dark_orange.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_dark_purple.9.png b/core/res/res/drawable-hdpi/sim_dark_purple.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_blue.9.png b/core/res/res/drawable-hdpi/sim_light_blue.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_green.9.png b/core/res/res/drawable-hdpi/sim_light_green.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_orange.9.png b/core/res/res/drawable-hdpi/sim_light_orange.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-hdpi/sim_light_purple.9.png b/core/res/res/drawable-hdpi/sim_light_purple.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_blue.9.png b/core/res/res/drawable-mdpi/sim_dark_blue.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_green.9.png b/core/res/res/drawable-mdpi/sim_dark_green.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_orange.9.png b/core/res/res/drawable-mdpi/sim_dark_orange.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_dark_purple.9.png b/core/res/res/drawable-mdpi/sim_dark_purple.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_blue.9.png b/core/res/res/drawable-mdpi/sim_light_blue.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_green.9.png b/core/res/res/drawable-mdpi/sim_light_green.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_orange.9.png b/core/res/res/drawable-mdpi/sim_light_orange.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-mdpi/sim_light_purple.9.png b/core/res/res/drawable-mdpi/sim_light_purple.9.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/ic_audio_notification_am_alpha.png b/core/res/res/drawable-xxhdpi/ic_audio_notification_am_alpha.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_car_mode.png b/core/res/res/drawable-xxhdpi/stat_notify_car_mode.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_disk_full.png b/core/res/res/drawable-xxhdpi/stat_notify_disk_full.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_email_generic.png b/core/res/res/drawable-xxhdpi/stat_notify_email_generic.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_gmail.png b/core/res/res/drawable-xxhdpi/stat_notify_gmail.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_more.png b/core/res/res/drawable-xxhdpi/stat_notify_more.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard_prepare.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_prepare.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sdcard_usb.png b/core/res/res/drawable-xxhdpi/stat_notify_sdcard_usb.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sim_toolkit.png b/core/res/res/drawable-xxhdpi/stat_notify_sim_toolkit.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync.png b/core/res/res/drawable-xxhdpi/stat_notify_sync.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync_anim0.png b/core/res/res/drawable-xxhdpi/stat_notify_sync_anim0.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_sync_error.png b/core/res/res/drawable-xxhdpi/stat_notify_sync_error.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_notify_voicemail.png b/core/res/res/drawable-xxhdpi/stat_notify_voicemail.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_bluetooth.png b/core/res/res/drawable-xxhdpi/stat_sys_data_bluetooth.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_data_usb.png b/core/res/res/drawable-xxhdpi/stat_sys_data_usb.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim0.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim0.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim1.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim1.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim2.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim2.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim3.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim3.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim4.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim4.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_download_anim5.png b/core/res/res/drawable-xxhdpi/stat_sys_download_anim5.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png b/core/res/res/drawable-xxhdpi/stat_sys_gps_on.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_throttled.png b/core/res/res/drawable-xxhdpi/stat_sys_throttled.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim0.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim0.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim1.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim2.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim3.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim3.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim4.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim4.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_upload_anim5.png b/core/res/res/drawable-xxhdpi/stat_sys_upload_anim5.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/stat_sys_warning.png b/core/res/res/drawable-xxhdpi/stat_sys_warning.png
old mode 100755
new mode 100644
Binary files differ
diff --git a/core/res/res/drawable/edit_text_material.xml b/core/res/res/drawable/edit_text_material.xml
index 38ac567..901b3dc 100644
--- a/core/res/res/drawable/edit_text_material.xml
+++ b/core/res/res/drawable/edit_text_material.xml
@@ -22,8 +22,7 @@
     <selector>
         <item android:state_enabled="false">
             <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
-                android:tint="?attr/colorControlNormal"
-                android:alpha="?attr/disabledAlpha" />
+                android:tint="?attr/colorControlNormal" />
         </item>
         <item android:state_pressed="false" android:state_focused="false">
             <nine-patch android:src="@drawable/textfield_default_mtrl_alpha"
diff --git a/core/res/res/drawable/scrollbar_handle_material.xml b/core/res/res/drawable/scrollbar_handle_material.xml
index 56fecec..33efbba 100644
--- a/core/res/res/drawable/scrollbar_handle_material.xml
+++ b/core/res/res/drawable/scrollbar_handle_material.xml
@@ -17,6 +17,9 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:tint="?attr/colorControlNormal"
        android:shape="rectangle">
-    <solid android:color="#84ffffff" />
-    <size android:width="4dp" />
+    <solid
+        android:color="#84ffffff" />
+    <size
+        android:width="4dp"
+        android:height="4dp" />
 </shape>
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/values-af-watch/strings.xml b/core/res/res/values-af-watch/strings.xml
index c81848a..ee43129 100644
--- a/core/res/res/values-af-watch/strings.xml
+++ b/core/res/res/values-af-watch/strings.xml
@@ -21,4 +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>
+    <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 95188b6..ee6ed57 100644
--- a/core/res/res/values-am-watch/strings.xml
+++ b/core/res/res/values-am-watch/strings.xml
@@ -21,4 +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>
+    <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 8cbb0a5..af6a164 100644
--- a/core/res/res/values-ar-watch/strings.xml
+++ b/core/res/res/values-ar-watch/strings.xml
@@ -21,4 +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>
+    <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 7e4a762..5a84880 100644
--- a/core/res/res/values-az-rAZ-watch/strings.xml
+++ b/core/res/res/values-az-rAZ-watch/strings.xml
@@ -21,4 +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>
+    <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 1f1d921..5eb2a02 100644
--- a/core/res/res/values-bg-watch/strings.xml
+++ b/core/res/res/values-bg-watch/strings.xml
@@ -21,4 +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>
+    <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 b934841..4ef2d6ea 100644
--- a/core/res/res/values-bn-rBD-watch/strings.xml
+++ b/core/res/res/values-bn-rBD-watch/strings.xml
@@ -21,4 +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>
+    <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 b44703e..b01ca63 100644
--- a/core/res/res/values-ca-watch/strings.xml
+++ b/core/res/res/values-ca-watch/strings.xml
@@ -21,4 +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>
+    <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">"ser 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 ruta de sortida del contingut multimèdia"</string>
+    <string name="permlab_readInstallSessionswear" msgid="9059478058685861989">"llegir les sessions d\'instal·lació"</string>
+    <string name="permlab_requestInstallPackageswear" msgid="4982025836783539503">"sol·licitar els paquets d\'instal·lació"</string>
 </resources>
diff --git a/core/res/res/values-cs-watch/strings.xml b/core/res/res/values-cs-watch/strings.xml
index 89c9dee..229e1eb 100644
--- a/core/res/res/values-cs-watch/strings.xml
+++ b/core/res/res/values-cs-watch/strings.xml
@@ -21,4 +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>
+    <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 f1daf30..094a50f 100644
--- a/core/res/res/values-da-watch/strings.xml
+++ b/core/res/res/values-da-watch/strings.xml
@@ -21,4 +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>
+    <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 52a21ba..6f5941b 100644
--- a/core/res/res/values-de-watch/strings.xml
+++ b/core/res/res/values-de-watch/strings.xml
@@ -21,4 +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>
+    <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 81a7451..8081013 100644
--- a/core/res/res/values-el-watch/strings.xml
+++ b/core/res/res/values-el-watch/strings.xml
@@ -21,4 +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>
+    <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 6734cd3..30357ce 100644
--- a/core/res/res/values-en-rAU-watch/strings.xml
+++ b/core/res/res/values-en-rAU-watch/strings.xml
@@ -21,4 +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>
+    <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 6734cd3..30357ce 100644
--- a/core/res/res/values-en-rGB-watch/strings.xml
+++ b/core/res/res/values-en-rGB-watch/strings.xml
@@ -21,4 +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>
+    <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 6734cd3..30357ce 100644
--- a/core/res/res/values-en-rIN-watch/strings.xml
+++ b/core/res/res/values-en-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 763b24d..703cb32 100644
--- a/core/res/res/values-es-rUS-watch/strings.xml
+++ b/core/res/res/values-es-rUS-watch/strings.xml
@@ -21,4 +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>
+    <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 d9ea0fe..7eedf0c 100644
--- a/core/res/res/values-es-watch/strings.xml
+++ b/core/res/res/values-es-watch/strings.xml
@@ -21,4 +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>
+    <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 0adb487..c554e38 100644
--- a/core/res/res/values-et-rEE-watch/strings.xml
+++ b/core/res/res/values-et-rEE-watch/strings.xml
@@ -21,4 +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>
+    <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 9c13ef9..011105e 100644
--- a/core/res/res/values-eu-rES-watch/strings.xml
+++ b/core/res/res/values-eu-rES-watch/strings.xml
@@ -21,4 +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>
+    <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-elementuak 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 a33d7ec..5fe8359 100644
--- a/core/res/res/values-fa-watch/strings.xml
+++ b/core/res/res/values-fa-watch/strings.xml
@@ -21,4 +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>
+    <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 89782a5..662e0ab 100644
--- a/core/res/res/values-fi-watch/strings.xml
+++ b/core/res/res/values-fi-watch/strings.xml
@@ -21,4 +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>
+    <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 ea9c1c2..8f2e683 100644
--- a/core/res/res/values-fr-rCA-watch/strings.xml
+++ b/core/res/res/values-fr-rCA-watch/strings.xml
@@ -21,4 +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>
+    <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 7e616cd..21bf8a6 100644
--- a/core/res/res/values-fr-watch/strings.xml
+++ b/core/res/res/values-fr-watch/strings.xml
@@ -21,4 +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>
+    <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 d9ea0fe..95d6400 100644
--- a/core/res/res/values-gl-rES-watch/strings.xml
+++ b/core/res/res/values-gl-rES-watch/strings.xml
@@ -21,4 +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>
+    <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 3e50335..af1b068 100644
--- a/core/res/res/values-gu-rIN-watch/strings.xml
+++ b/core/res/res/values-gu-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 148dab4..afed795 100644
--- a/core/res/res/values-hi-watch/strings.xml
+++ b/core/res/res/values-hi-watch/strings.xml
@@ -21,4 +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>
+    <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 4b88ac7..dda3cb2 100644
--- a/core/res/res/values-hr-watch/strings.xml
+++ b/core/res/res/values-hr-watch/strings.xml
@@ -21,4 +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>
+    <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 9f2e97f..7c45326 100644
--- a/core/res/res/values-hu-watch/strings.xml
+++ b/core/res/res/values-hu-watch/strings.xml
@@ -21,4 +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>
+    <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 265268e..9bff6ad 100644
--- a/core/res/res/values-hy-rAM-watch/strings.xml
+++ b/core/res/res/values-hy-rAM-watch/strings.xml
@@ -21,4 +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>
+    <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 947a7f1..ef88a11 100644
--- a/core/res/res/values-in-watch/strings.xml
+++ b/core/res/res/values-in-watch/strings.xml
@@ -21,4 +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>
+    <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 cb6da5c..d512b6e 100644
--- a/core/res/res/values-is-rIS-watch/strings.xml
+++ b/core/res/res/values-is-rIS-watch/strings.xml
@@ -21,4 +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>
+    <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 a042221..c348e48 100644
--- a/core/res/res/values-it-watch/strings.xml
+++ b/core/res/res/values-it-watch/strings.xml
@@ -21,4 +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>
+    <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 64b194d..1e4bad4 100644
--- a/core/res/res/values-iw-watch/strings.xml
+++ b/core/res/res/values-iw-watch/strings.xml
@@ -21,4 +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>
+    <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 b3c6d97..3248041 100644
--- a/core/res/res/values-ja-watch/strings.xml
+++ b/core/res/res/values-ja-watch/strings.xml
@@ -21,4 +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>
+    <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-ja/strings.xml b/core/res/res/values-ja/strings.xml
index e43a19c..545b963 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1024,7 +1024,7 @@
     <string name="usb_ptp_notification_title" msgid="1347328437083192112">"USBを写真転送に使用"</string>
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USBをMIDIに使用"</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-ka-rGE-watch/strings.xml b/core/res/res/values-ka-rGE-watch/strings.xml
index 4fe6d11..9e2ca1f 100644
--- a/core/res/res/values-ka-rGE-watch/strings.xml
+++ b/core/res/res/values-ka-rGE-watch/strings.xml
@@ -21,4 +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>
+    <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 583eb19..8c41688 100644
--- a/core/res/res/values-kk-rKZ-watch/strings.xml
+++ b/core/res/res/values-kk-rKZ-watch/strings.xml
@@ -21,4 +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>
+    <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 2b7e12f..5c1bf8a 100644
--- a/core/res/res/values-km-rKH-watch/strings.xml
+++ b/core/res/res/values-km-rKH-watch/strings.xml
@@ -21,4 +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>
+    <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 e01cee1..def2130 100644
--- a/core/res/res/values-kn-rIN-watch/strings.xml
+++ b/core/res/res/values-kn-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 df3288b..8602c7e 100644
--- a/core/res/res/values-ko-watch/strings.xml
+++ b/core/res/res/values-ko-watch/strings.xml
@@ -21,4 +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>
+    <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 3f167ac..2fb9047 100644
--- a/core/res/res/values-ky-rKG-watch/strings.xml
+++ b/core/res/res/values-ky-rKG-watch/strings.xml
@@ -21,4 +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>
+    <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 a8c9cd2..db2f7e4 100644
--- a/core/res/res/values-lo-rLA-watch/strings.xml
+++ b/core/res/res/values-lo-rLA-watch/strings.xml
@@ -21,4 +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>
+    <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 ed8ccdb..ce154e70 100644
--- a/core/res/res/values-lt-watch/strings.xml
+++ b/core/res/res/values-lt-watch/strings.xml
@@ -21,4 +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>
+    <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 a0d051e..c44677f 100644
--- a/core/res/res/values-lv-watch/strings.xml
+++ b/core/res/res/values-lv-watch/strings.xml
@@ -21,4 +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>
+    <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-mcc219-mnc02/config.xml b/core/res/res/values-mcc219-mnc02/config.xml
new file mode 100644
index 0000000..2ac6ba6
--- /dev/null
+++ b/core/res/res/values-mcc219-mnc02/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>21901</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 b4eb51a..9d7c5bf 100644
--- a/core/res/res/values-mk-rMK-watch/strings.xml
+++ b/core/res/res/values-mk-rMK-watch/strings.xml
@@ -21,4 +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>
+    <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 079c42f..02fe66c 100644
--- a/core/res/res/values-ml-rIN-watch/strings.xml
+++ b/core/res/res/values-ml-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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-mn-rMN-watch/strings.xml b/core/res/res/values-mn-rMN-watch/strings.xml
index 49f829b..6387aed 100644
--- a/core/res/res/values-mn-rMN-watch/strings.xml
+++ b/core/res/res/values-mn-rMN-watch/strings.xml
@@ -21,4 +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>
+    <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 49fa7d9..0a60aad 100644
--- a/core/res/res/values-mr-rIN-watch/strings.xml
+++ b/core/res/res/values-mr-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 148f518..c3f68b8 100644
--- a/core/res/res/values-ms-rMY-watch/strings.xml
+++ b/core/res/res/values-ms-rMY-watch/strings.xml
@@ -21,4 +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>
+    <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 ec89e53..c4d738a 100644
--- a/core/res/res/values-my-rMM-watch/strings.xml
+++ b/core/res/res/values-my-rMM-watch/strings.xml
@@ -21,4 +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>
+    <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 3bd7fa5..249026c 100644
--- a/core/res/res/values-nb-watch/strings.xml
+++ b/core/res/res/values-nb-watch/strings.xml
@@ -21,4 +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>
+    <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 e2453c89..a38de99 100644
--- a/core/res/res/values-ne-rNP-watch/strings.xml
+++ b/core/res/res/values-ne-rNP-watch/strings.xml
@@ -21,4 +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>
+    <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 989fa27..590d146 100644
--- a/core/res/res/values-nl-watch/strings.xml
+++ b/core/res/res/values-nl-watch/strings.xml
@@ -21,4 +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>
+    <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-nl/strings.xml b/core/res/res/values-nl/strings.xml
index cfdd69b..d77dca1f 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -39,7 +39,7 @@
     <string name="durationMinuteSecond" msgid="3989228718067466680">"<xliff:g id="MINUTES">%1$d</xliff:g> min <xliff:g id="SECONDS">%2$d</xliff:g> sec"</string>
     <string name="durationSeconds" msgid="8050088505238241405">"<xliff:g id="SECONDS">%1$d</xliff:g> seconden"</string>
     <string name="durationSecond" msgid="985669622276420331">"<xliff:g id="SECONDS">%1$d</xliff:g> seconde"</string>
-    <string name="untitled" msgid="4638956954852782576">"&lt;Zonder titel&gt;"</string>
+    <string name="untitled" msgid="4638956954852782576">"&lt;Naamloos&gt;"</string>
     <string name="emptyPhoneNumber" msgid="7694063042079676517">"(Geen telefoonnummer)"</string>
     <string name="unknownName" msgid="6867811765370350269">"Onbekend"</string>
     <string name="defaultVoiceMailAlphaTag" msgid="2660020990097733077">"Voicemail"</string>
diff --git a/core/res/res/values-pa-rIN-watch/strings.xml b/core/res/res/values-pa-rIN-watch/strings.xml
index b30daa4..e5cb9e1 100644
--- a/core/res/res/values-pa-rIN-watch/strings.xml
+++ b/core/res/res/values-pa-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 d9608f3..ff9f7ea 100644
--- a/core/res/res/values-pl-watch/strings.xml
+++ b/core/res/res/values-pl-watch/strings.xml
@@ -21,4 +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>
+    <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 120e4a5..a5e4a11 100644
--- a/core/res/res/values-pt-rBR-watch/strings.xml
+++ b/core/res/res/values-pt-rBR-watch/strings.xml
@@ -21,4 +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>
+    <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 69d2c0a..0dd354a 100644
--- a/core/res/res/values-pt-rPT-watch/strings.xml
+++ b/core/res/res/values-pt-rPT-watch/strings.xml
@@ -21,4 +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>
+    <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 120e4a5..a5e4a11 100644
--- a/core/res/res/values-pt-watch/strings.xml
+++ b/core/res/res/values-pt-watch/strings.xml
@@ -21,4 +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>
+    <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 95c8ec3..e412cad 100644
--- a/core/res/res/values-ro-watch/strings.xml
+++ b/core/res/res/values-ro-watch/strings.xml
@@ -21,4 +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>
+    <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-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 2cf1d1e..d215d4c 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -50,7 +50,7 @@
     <string name="serviceEnabledFor" msgid="6856228140453471041">"Serviciul a fost activat pentru:"</string>
     <string name="serviceDisabled" msgid="1937553226592516411">"Serviciul a fost dezactivat."</string>
     <string name="serviceRegistered" msgid="6275019082598102493">"Înregistrarea a reuşit."</string>
-    <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reuşit."</string>
+    <string name="serviceErased" msgid="1288584695297200972">"Ștergerea a reușit."</string>
     <string name="passwordIncorrect" msgid="7612208839450128715">"Parolă incorectă."</string>
     <string name="mmiComplete" msgid="8232527495411698359">"MMI finalizat."</string>
     <string name="badPin" msgid="9015277645546710014">"Codul PIN vechi introdus nu este corect."</string>
@@ -59,7 +59,7 @@
     <string name="invalidPin" msgid="3850018445187475377">"Introduceţi un cod PIN alcătuit din 4 până la 8 cifre."</string>
     <string name="invalidPuk" msgid="8761456210898036513">"Introduceţi un cod PUK care să aibă 8 cifre sau mai mult."</string>
     <string name="needPuk" msgid="919668385956251611">"Cardul SIM este blocat cu codul PUK. Introduceţi codul PUK pentru a-l debloca."</string>
-    <string name="needPuk2" msgid="4526033371987193070">"Introduceţi codul PUK2 pentru a debloca cardul SIM."</string>
+    <string name="needPuk2" msgid="4526033371987193070">"Introduceți codul PUK2 pentru a debloca cardul SIM."</string>
     <string name="enablePin" msgid="209412020907207950">"Operațiunea nu a reușit. Activați blocarea cardului SIM/RUIM."</string>
     <plurals name="pinpuk_attempts" formatted="false" msgid="1251012001539225582">
       <item quantity="few">V-au mai rămas <xliff:g id="NUMBER_1">%d</xliff:g> încercări până la blocarea cardului SIM.</item>
@@ -85,8 +85,8 @@
     <string name="DndMmi" msgid="1265478932418334331">"Nu deranjaţi"</string>
     <string name="CLIRDefaultOnNextCallOn" msgid="429415409145781923">"ID-ul apelantului este restricţionat în mod prestabilit. Apelul următor: restricţionat"</string>
     <string name="CLIRDefaultOnNextCallOff" msgid="3092918006077864624">"ID-ul apelantului este restricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
-    <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricţionat în mod prestabilit. Apelul următor: Restricţionat."</string>
-    <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricţionat în mod prestabilit. Apelul următor: nerestricţionat"</string>
+    <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: Restricționat."</string>
+    <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"ID-ul apelantului este nerestricționat în mod prestabilit. Apelul următor: nerestricționat"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"Nu se asigură accesul la acest serviciu."</string>
     <string name="CLIRPermanent" msgid="3377371145926835671">"Nu puteți să modificaţi setarea pentru ID-ul apelantului."</string>
     <string name="RestrictedChangedTitle" msgid="5592189398956187498">"Acces restricționat modificat"</string>
@@ -181,7 +181,7 @@
     <string name="power_dialog" product="tv" msgid="6153888706430556356">"Opțiuni TV"</string>
     <string name="power_dialog" product="default" msgid="1319919075463988638">"Opţiuni telefon"</string>
     <string name="silent_mode" msgid="7167703389802618663">"Mod Silențios"</string>
-    <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcţia wireless"</string>
+    <string name="turn_on_radio" msgid="3912793092339962371">"Activați funcția wireless"</string>
     <string name="turn_off_radio" msgid="8198784949987062346">"Dezactivați funcția wireless"</string>
     <string name="screen_lock" msgid="799094655496098153">"Blocați ecranul"</string>
     <string name="power_off" msgid="4266614107412865048">"Opriți alimentarea"</string>
@@ -266,9 +266,9 @@
     <string name="permlab_processOutgoingCalls" msgid="3906007831192990946">"redirecţionează apelurile efectuate"</string>
     <string name="permdesc_processOutgoingCalls" msgid="5156385005547315876">"Permite aplicației să vadă numărul format în timpul unui apel de ieșire, cu opțiunea de a redirecționa apelul către un alt număr sau de a întrerupe apelul."</string>
     <string name="permlab_receiveSms" msgid="8673471768947895082">"primeşte mesaje text (SMS)"</string>
-    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
+    <string name="permdesc_receiveSms" msgid="6424387754228766939">"Permite aplicației să primească și să proceseze mesaje SMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
     <string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
-    <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau şterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
+    <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citeşte mesajele cu transmisie celulară"</string>
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
@@ -280,7 +280,7 @@
     <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
     <string name="permdesc_readSms" product="default" msgid="3695967533457240550">"Permite aplicației să citească mesajele SMS stocate pe telefon sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
     <string name="permlab_receiveWapPush" msgid="5991398711936590410">"primeşte mesaje text (WAP)"</string>
-    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau şterge mesajele care v-au fost trimise fără a vi le arăta."</string>
+    <string name="permdesc_receiveWapPush" msgid="748232190220583385">"Permite aplicației să primească și să proceseze mesaje WAP. Această permisiune include capacitatea de a monitoriza sau șterge mesajele care v-au fost trimise fără a vi le arăta."</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"preluare aplicații care rulează"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"Permite aplicației să preia informațiile despre activităţile care rulează în prezent și care au rulat recent. În acest fel, aplicația poate descoperi informații despre aplicațiile care sunt utilizate pe dispozitiv."</string>
     <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"Gestionează proprietarii de profiluri și proprietarul dispozitivului"</string>
@@ -314,17 +314,17 @@
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
     <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
-    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate şterge datele de contact."</string>
+    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
-    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate şterge datele de contact."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
     <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
-    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a şterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+    <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
-    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a şterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
+    <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Permite aplicației să modifice jurnalul de apeluri al telefonului dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
     <string name="permlab_bodySensors" msgid="4871091374767171066">"senzori (ex.: senzori de ritm cardiac)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Permite aplicației să acceseze date de la senzorii care vă monitorizează starea fizică, cum ar fi ritmul cardiac."</string>
     <string name="permlab_readCalendar" msgid="5972727560257612398">"citirea evenimentelor din calendar și a informaţiilor confidenţiale"</string>
@@ -335,7 +335,7 @@
     <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
     <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
-    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locaţiei"</string>
+    <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe rețea și GPS)"</string>
     <string name="permdesc_accessFineLocation" msgid="5295047563564981250">"Permite aplicației să obţină locaţia dvs. exactă utilizând sistemul GPS (Global Positioning System) sau surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. și pot să consume mai multă energie a bateriei."</string>
@@ -446,8 +446,8 @@
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"citeşte conţinutul cardului SD"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Permite aplic. citirea conținutului stoc. USB."</string>
     <string name="permdesc_sdcardRead" product="default" msgid="2607362473654975411">"Permite aplicației citirea conținutul cardului SD."</string>
-    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau şterge conţinutul stocării USB"</string>
-    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau şterge conţinutul cardului SD"</string>
+    <string name="permlab_sdcardWrite" product="nosdcard" msgid="8485979062254666748">"modifică sau șterge conţinutul stocării USB"</string>
+    <string name="permlab_sdcardWrite" product="default" msgid="8805693630050458763">"modifică sau șterge conţinutul cardului SD"</string>
     <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6175406299445710888">"Permite scriere în stoc. USB."</string>
     <string name="permdesc_sdcardWrite" product="default" msgid="4337417790936632090">"Permite aplicației să scrie pe cardul SD."</string>
     <string name="permlab_use_sip" msgid="2052499390128979920">"efectuarea/primirea apelurilor SIP"</string>
@@ -650,10 +650,10 @@
     <string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"Introduceţi codul PIN pentru a debloca"</string>
     <string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"Cod PIN incorect."</string>
     <string name="keyguard_label_text" msgid="861796461028298424">"Pentru a debloca, apăsaţi Meniu, apoi 0."</string>
-    <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgenţă"</string>
+    <string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Număr de urgență"</string>
     <string name="lockscreen_carrier_default" msgid="8963839242565653192">"Fără serviciu."</string>
     <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Ecranul este blocat."</string>
-    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsaţi Meniu pentru a debloca sau pentru a efectua apeluri de urgenţă."</string>
+    <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Apăsați Meniu pentru a debloca sau pentru a efectua apeluri de urgență."</string>
     <string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Apăsaţi Meniu pentru deblocare."</string>
     <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Desenaţi modelul pentru a debloca"</string>
     <string name="lockscreen_emergency_call" msgid="5298642613417801888">"Urgență"</string>
@@ -710,7 +710,7 @@
     <string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Sunet activat"</string>
     <string name="lockscreen_sound_off_label" msgid="996822825154319026">"Sunet dezactivat"</string>
     <string name="lockscreen_access_pattern_start" msgid="3941045502933142847">"Desenarea modelului a început"</string>
-    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Modelul a fost şters"</string>
+    <string name="lockscreen_access_pattern_cleared" msgid="5583479721001639579">"Modelul a fost șters"</string>
     <string name="lockscreen_access_pattern_cell_added" msgid="6756031208359292487">"Celulă adăugată"</string>
     <string name="lockscreen_access_pattern_cell_added_verbose" msgid="7264580781744026939">"Celula <xliff:g id="CELL_INDEX">%1$s</xliff:g> a fost adăugată"</string>
     <string name="lockscreen_access_pattern_detected" msgid="4988730895554057058">"Modelul a fost desenat"</string>
@@ -755,7 +755,7 @@
     <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Părăsiți această pagină"</string>
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string>
-    <string name="save_password_label" msgid="6860261758665825069">"Confirmaţi"</string>
+    <string name="save_password_label" msgid="6860261758665825069">"Confirmați"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi și micşoraţi prin dublă atingere."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"Conf.Compl.auto."</string>
@@ -778,9 +778,9 @@
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citeşte marcajele și istoricul web"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate şterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
@@ -795,7 +795,7 @@
     <string name="text_copied" msgid="4985729524670131385">"Text copiat în clipboard."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Mai multe"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Meniu+"</string>
-    <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spaţiu"</string>
+    <string name="menu_space_shortcut_label" msgid="2410328639272162537">"spațiu"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string>
     <string name="search_go" msgid="8298016669822141719">"Căutați"</string>
@@ -1140,8 +1140,8 @@
       <item quantity="one">Un rezultat</item>
     </plurals>
     <string name="action_mode_done" msgid="7217581640461922289">"Terminat"</string>
-    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Se şterge stocarea USB..."</string>
-    <string name="progress_erasing" product="default" msgid="6596988875507043042">"Se şterge cardul SD..."</string>
+    <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"Se șterge stocarea USB..."</string>
+    <string name="progress_erasing" product="default" msgid="6596988875507043042">"Se șterge cardul SD..."</string>
     <string name="share" msgid="1778686618230011964">"Distribuiţi"</string>
     <string name="find" msgid="4808270900322985960">"Găsiţi"</string>
     <string name="websearch" msgid="4337157977400211589">"Căutare pe web"</string>
diff --git a/core/res/res/values-ru-watch/strings.xml b/core/res/res/values-ru-watch/strings.xml
index f32f63b..5dd5630 100644
--- a/core/res/res/values-ru-watch/strings.xml
+++ b/core/res/res/values-ru-watch/strings.xml
@@ -21,4 +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>
+    <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 b55687f..aad82a0 100644
--- a/core/res/res/values-si-rLK-watch/strings.xml
+++ b/core/res/res/values-si-rLK-watch/strings.xml
@@ -21,4 +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>
+    <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 601c016..765b390 100644
--- a/core/res/res/values-sk-watch/strings.xml
+++ b/core/res/res/values-sk-watch/strings.xml
@@ -21,4 +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>
+    <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 bf1190f..f138326 100644
--- a/core/res/res/values-sl-watch/strings.xml
+++ b/core/res/res/values-sl-watch/strings.xml
@@ -21,4 +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>
+    <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 d1637ba..7e36a32 100644
--- a/core/res/res/values-sq-rAL-watch/strings.xml
+++ b/core/res/res/values-sq-rAL-watch/strings.xml
@@ -21,4 +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>
+    <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 484977e..afeae38 100644
--- a/core/res/res/values-sr-watch/strings.xml
+++ b/core/res/res/values-sr-watch/strings.xml
@@ -21,4 +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>
+    <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 3bd7fa5..439b464 100644
--- a/core/res/res/values-sv-watch/strings.xml
+++ b/core/res/res/values-sv-watch/strings.xml
@@ -21,4 +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>
+    <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 5a8c72e..3cad827 100644
--- a/core/res/res/values-sw-watch/strings.xml
+++ b/core/res/res/values-sw-watch/strings.xml
@@ -21,4 +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>
+    <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 4c05cab..63e072f 100644
--- a/core/res/res/values-ta-rIN-watch/strings.xml
+++ b/core/res/res/values-ta-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 6b4b900..f642807 100644
--- a/core/res/res/values-te-rIN-watch/strings.xml
+++ b/core/res/res/values-te-rIN-watch/strings.xml
@@ -21,4 +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>
+    <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 568b083..98f938d 100644
--- a/core/res/res/values-th-watch/strings.xml
+++ b/core/res/res/values-th-watch/strings.xml
@@ -21,4 +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>
+    <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 bb0dc4b..c38891e 100644
--- a/core/res/res/values-tl-watch/strings.xml
+++ b/core/res/res/values-tl-watch/strings.xml
@@ -21,4 +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>
+    <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 d9c3923..4dbf664 100644
--- a/core/res/res/values-tr-watch/strings.xml
+++ b/core/res/res/values-tr-watch/strings.xml
@@ -21,4 +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>
+    <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 02e6466..63ddea9 100644
--- a/core/res/res/values-uk-watch/strings.xml
+++ b/core/res/res/values-uk-watch/strings.xml
@@ -21,4 +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>
+    <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 0fd24c9..8ba8042 100644
--- a/core/res/res/values-ur-rPK-watch/strings.xml
+++ b/core/res/res/values-ur-rPK-watch/strings.xml
@@ -21,4 +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>
+    <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-uz-rUZ-watch/strings.xml b/core/res/res/values-uz-rUZ-watch/strings.xml
index 7abd603..0fe54a1 100644
--- a/core/res/res/values-uz-rUZ-watch/strings.xml
+++ b/core/res/res/values-uz-rUZ-watch/strings.xml
@@ -21,4 +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>
+    <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 f419bdf..8bfd3df 100644
--- a/core/res/res/values-vi-watch/strings.xml
+++ b/core/res/res/values-vi-watch/strings.xml
@@ -21,4 +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>
+    <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-watch/strings.xml b/core/res/res/values-watch/strings.xml
index 4ea2b52..e5991fc 100644
--- a/core/res/res/values-watch/strings.xml
+++ b/core/res/res/values-watch/strings.xml
@@ -23,4 +23,50 @@
     <string name="android_upgrading_apk">App
         <xliff:g id="number" example="123">%1$d</xliff:g> of
         <xliff:g id="number" example="123">%2$d</xliff:g>.</string>
+
+    <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. Override from base which says "Body Sensors". [CHAR_LIMIT=25] -->
+    <string name="permgrouplab_sensors">Sensors</string>
+
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_contactswear">access your contacts</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_locationwear">access this watch\'s location</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_calendarwear">access your calendar</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_smswear">send and view SMS messages</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_storagewear">access photos, media, and files on your watch</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_microphonewear">record audio</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_camerawear">take pictures and record video</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_phonewear">make and manage phone calls</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permgrouplab_sensorswear">access sensor data about your vital signs</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_statusBarServicewear">be the status bar</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_bodySensorswear">access body sensors (like heart rate monitors)</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_accessFineLocationwear">access precise location (GPS and network-based)</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_accessCoarseLocationwear">access approximate location (network-based)</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_sim_communicationwear">send commands to the SIM</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_createNetworkSocketswear">have full network access</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_manageProfileAndDeviceOwnerswear">manage profile and device owners</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_changeWimaxStatewear">change WiMAX state</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_handoverStatuswear">receive Android Beam transfer status</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_route_media_outputwear">route media output</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_readInstallSessionswear">read install sessions</string>
+    <!-- Description of a  permissions, listed so the user can choose whether they want to allow the application to do this. [CHAR_LIMIT=100] -->
+    <string name="permlab_requestInstallPackageswear">request install packages</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 9c9e49d..f336907 100644
--- a/core/res/res/values-zh-rCN-watch/strings.xml
+++ b/core/res/res/values-zh-rCN-watch/strings.xml
@@ -21,4 +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>
+    <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 3b5fb8e..b5ecb08 100644
--- a/core/res/res/values-zh-rHK-watch/strings.xml
+++ b/core/res/res/values-zh-rHK-watch/strings.xml
@@ -21,4 +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>
+    <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 87f3abb..79fb99d 100644
--- a/core/res/res/values-zh-rTW-watch/strings.xml
+++ b/core/res/res/values-zh-rTW-watch/strings.xml
@@ -21,4 +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>
+    <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 acd153b..e9121b9 100644
--- a/core/res/res/values-zu-watch/strings.xml
+++ b/core/res/res/values-zu-watch/strings.xml
@@ -21,4 +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>
+    <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_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 1a45b3a..4531f75 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1816,9 +1816,9 @@
         <attr name="uiOptions" />
         <attr name="parentActivityName" />
         <attr name="singleUser" />
-        <!-- @hide This broacast receiver will only receive broadcasts for the
-             primary user.  Can only be used with receivers. -->
-        <attr name="primaryUserOnly" format="boolean" />
+        <!-- @hide This broadcast receiver or activity will only receive broadcasts for the
+             system user-->
+        <attr name="systemUserOnly" format="boolean" />
         <attr name="persistableMode" />
         <attr name="allowEmbedded" />
         <attr name="documentLaunchMode" />
@@ -2195,4 +2195,18 @@
       <attr name="name" />
     </declare-styleable>
 
+    <!-- <code>initial-layout</code> tag allows configuring the initial layout for the activity
+         within multi-window environment. -->
+    <declare-styleable name="AndroidManifestInitialLayout" parent="AndroidManifestActivity">
+        <!-- Initial width of the activity. Can be either a fixed value or fraction, in which case
+             the width will be constructed as a fraction of the total available width. -->
+        <attr name="activityWidth" format="dimension|fraction" />
+        <!-- Initial height of the activity. Can be either a fixed value or fraction, in which case
+             the height will be constructed as a fraction of the total available height. -->
+        <attr name="activityHeight" format="dimension|fraction" />
+        <!-- Where to initially position the activity inside the available space. Uses constants
+             defined in {@link android.view.Gravity}. -->
+        <attr name="gravity" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7acc25d..ef4e261 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -619,6 +619,17 @@
         <!-- rotation: 270 (rotate CW)  --> <item>-25</item> <item>65</item>
     </integer-array>
 
+    <!-- Indicate the name of the window orientation sensor type if present. A
+         window orientation sensor produces values to be used in lieu of the
+         typical, accelerometer based sensor. It must only produce integral
+         values between 0 and 3, inclusive, with each one corresponding to a
+         given rotation:
+            0: 0 degrees of rotation (natural)
+            1: 90 degrees of rotation (rotate CCW)
+            2: 180 degrees of rotation (reverse)
+            3: 270 degrees of rotation (rotate CW) -->
+    <string name="config_orientationSensorType" translatable="false">@null</string>
+
     <!-- Lid switch behavior -->
 
     <!-- The number of degrees to rotate the display when the keyboard is open.
@@ -2018,10 +2029,6 @@
         IMS service implementation will do both.i.e.hold followed by merge. -->
     <bool name="skipHoldBeforeMerge">true</bool>
 
-    <!-- Flag indicating emergency calls will always use IMS irrespective of the state of
-    the IMS connection -->
-    <bool name="useImsAlwaysForEmergencyCall">true</bool>
-
     <!-- Flag indicating whether the IMS service can be turned off. If false then
         the service will not be turned-off completely (the ImsManager.turnOffIms() will
         be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cabb56c..d2089cd 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2679,5 +2679,7 @@
     <public type="style" name="Theme.Material.DayNight.DialogWhenLarge.DarkActionBar" />
 
     <public type="id" name="accessibilityActionSetProgress" />
+    <public type="attr" name="activityWidth" />
+    <public type="attr" name="activityHeight" />
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 004407f..e04c743 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1545,6 +1545,7 @@
   <java-symbol type="string" name="bugreport_title" />
   <java-symbol type="string" name="bugreport_message" />
   <java-symbol type="string" name="bugreport_status" />
+  <java-symbol type="string" name="config_orientationSensorType" />
   <java-symbol type="string" name="faceunlock_multiple_failures" />
   <java-symbol type="string" name="global_action_power_off" />
   <java-symbol type="string" name="global_actions_airplane_mode_off_status" />
@@ -2137,7 +2138,6 @@
   <java-symbol type="bool" name="config_carrier_vt_available" />
   <java-symbol type="bool" name="config_device_wfc_ims_available" />
   <java-symbol type="bool" name="config_carrier_wfc_ims_available" />
-  <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" />
   <java-symbol type="attr" name="touchscreenBlocksFocus" />
   <java-symbol type="layout" name="resolver_list_with_default" />
   <java-symbol type="string" name="whichApplicationNamed" />
diff --git a/core/tests/coretests/src/android/animation/ValueAnimatorTests.java b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
new file mode 100644
index 0000000..6d20503
--- /dev/null
+++ b/core/tests/coretests/src/android/animation/ValueAnimatorTests.java
@@ -0,0 +1,897 @@
+/*
+* 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.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;
+
+    // Tolerance of error in calculations related to duration, frame time, etc. due to frame delay.
+    private final static long TOLERANCE = 100; // ms
+    private final static long POLL_INTERVAL = 100; // ms
+
+    private final static float A1_START_VALUE = 0f;
+    private final static float A1_END_VALUE = 1f;
+    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);
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        a1 = ValueAnimator.ofFloat(A1_START_VALUE, A1_END_VALUE).setDuration(300);
+        a2 = ValueAnimator.ofInt(A2_START_VALUE, A2_END_VALUE).setDuration(500);
+    }
+
+    @Override
+    public void tearDown() throws Exception {
+        a1 = null;
+        a2 = null;
+        super.tearDown();
+    }
+
+    @SmallTest
+    public void testStartDelay() throws Throwable {
+        final ValueAnimator a = ValueAnimator.ofFloat(5f, 20f);
+        assertEquals(a.getStartDelay(), 0);
+        final long delay = 200;
+        a.setStartDelay(delay);
+        assertEquals(a.getStartDelay(), delay);
+
+        final MyUpdateListener listener = new MyUpdateListener();
+        a.addUpdateListener(listener);
+        final long[] startTime = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Test the time between isRunning() and isStarted()
+                assertFalse(a.isStarted());
+                assertFalse(a.isRunning());
+                a.start();
+                startTime[0] = SystemClock.uptimeMillis();
+                assertTrue(a.isStarted());
+                assertFalse(a.isRunning());
+            }
+        });
+
+        Thread.sleep(a.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(listener.wasRunning);
+                assertTrue(listener.firstRunningFrameTime - startTime[0] >= delay);
+            }
+        });
+
+        Thread.sleep(a.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a.isStarted());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testListenerCallbacks() throws Throwable {
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a2.setStartDelay(400);
+
+        assertFalse(l1.startCalled);
+        assertFalse(l1.cancelCalled);
+        assertFalse(l1.endCalled);
+        assertFalse(l2.startCalled);
+        assertFalse(l2.cancelCalled);
+        assertFalse(l2.endCalled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+            }
+        });
+
+        long wait = 0;
+        Thread.sleep(POLL_INTERVAL);
+        wait += POLL_INTERVAL;
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.cancelCalled);
+                a1.cancel();
+                assertTrue(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+            }
+        });
+
+        while (wait < a2.getStartDelay()) {
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    // Make sure a2's start listener isn't called during start delay.
+                    assertTrue(l1.startCalled);
+                    assertFalse(l2.startCalled);
+                }
+            });
+            Thread.sleep(POLL_INTERVAL);
+            wait += POLL_INTERVAL;
+        }
+
+        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) + TOLERANCE;
+        Thread.sleep(delay);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // a1 is canceled.
+                assertTrue(l1.startCalled);
+                assertTrue(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+
+                // a2 is supposed to finish normally
+                assertTrue(l2.startCalled);
+                assertFalse(l2.cancelCalled);
+                assertTrue(l2.endCalled);
+            }
+        });
+    }
+
+    @SmallTest
+    public void testIsStarted() throws Throwable {
+        assertFalse(a1.isStarted());
+        assertFalse(a2.isStarted());
+        assertFalse(a1.isRunning());
+        assertFalse(a2.isRunning());
+        final long startDelay = 150;
+        a1.setStartDelay(startDelay);
+        final long[] startTime = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+                startTime[0] = SystemClock.uptimeMillis();
+                assertTrue(a1.isStarted());
+                assertTrue(a2.isStarted());
+            }
+        });
+        long delayMs = 0;
+        while (delayMs < startDelay) {
+            Thread.sleep(POLL_INTERVAL);
+            delayMs += POLL_INTERVAL;
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (SystemClock.uptimeMillis() - startTime[0] < startDelay) {
+                        assertFalse(a1.isRunning());
+                    }
+                }
+            });
+        }
+
+        Thread.sleep(startDelay);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isRunning());
+            }
+        });
+
+        long delay = Math.max(a1.getTotalDuration(), a2.getTotalDuration()) * 2;
+        Thread.sleep(delay);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isRunning());
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+            }
+        });
+    }
+
+    @SmallTest
+    public void testPause() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(a1.isPaused());
+                assertFalse(a2.isPaused());
+
+                a1.start();
+                a2.start();
+
+                assertFalse(a1.isPaused());
+                assertFalse(a2.isPaused());
+                assertTrue(a1.isStarted());
+                assertTrue(a2.isStarted());
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a2.isRunning());
+                a1.pause();
+                assertTrue(a1.isPaused());
+                assertFalse(a2.isPaused());
+                assertTrue(a1.isRunning());
+            }
+        });
+
+        Thread.sleep(a2.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // By this time, a2 should have finished, and a1 is still paused
+                assertFalse(a2.isStarted());
+                assertFalse(a2.isRunning());
+                assertTrue(a1.isStarted());
+                assertTrue(a1.isRunning());
+                assertTrue(a1.isPaused());
+
+                a1.resume();
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(a1.isRunning());
+                assertTrue(a1.isStarted());
+                assertFalse(a1.isPaused());
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration());
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // a1 should finish by now.
+                assertFalse(a1.isRunning());
+                assertFalse(a1.isStarted());
+                assertFalse(a1.isPaused());
+            }
+        });
+
+    }
+
+    @SmallTest
+    public void testPauseListener() throws Throwable {
+        MyPauseListener l1 = new MyPauseListener();
+        MyPauseListener l2 = new MyPauseListener();
+        a1.addPauseListener(l1);
+        a2.addPauseListener(l2);
+
+        assertFalse(l1.pauseCalled);
+        assertFalse(l1.resumeCalled);
+        assertFalse(l2.pauseCalled);
+        assertFalse(l2.resumeCalled);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration() / 2);
+        a1.pause();
+
+        Thread.sleep(a2.getTotalDuration());
+
+        // Only a1's pause listener should be called.
+        assertTrue(l1.pauseCalled);
+        assertFalse(l1.resumeCalled);
+        a1.resume();
+
+        Thread.sleep(a1.getTotalDuration());
+
+        assertTrue(l1.pauseCalled);
+        assertTrue(l1.resumeCalled);
+        assertFalse(l2.pauseCalled);
+        assertFalse(l2.resumeCalled);
+    }
+
+    @SmallTest
+    public void testResume() throws Throwable {
+        final MyUpdateListener l1 = new MyUpdateListener();
+        final long totalDuration = a1.getTotalDuration();
+        a1.addUpdateListener(l1);
+        // Set a longer duration on a1 for this test
+        a1.setDuration(1000);
+        assertTrue(l1.firstRunningFrameTime < 0);
+        assertTrue(l1.lastUpdateTime < 0);
+
+        final long[] lastUpdate = new long[1];
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+            }
+        });
+
+        Thread.sleep(totalDuration / 2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(l1.firstRunningFrameTime > 0);
+                assertTrue(l1.lastUpdateTime > l1.firstRunningFrameTime);
+                lastUpdate[0] = l1.lastUpdateTime;
+                a1.pause();
+            }
+        });
+
+        Thread.sleep(totalDuration);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // There should be no update after pause()
+                assertEquals(lastUpdate[0], l1.lastUpdateTime);
+                a1.resume();
+            }
+        });
+
+        do {
+            Thread.sleep(POLL_INTERVAL);
+            runTestOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    assertTrue(l1.lastUpdateTime > lastUpdate[0]);
+                    lastUpdate[0] = l1.lastUpdateTime;
+                }
+            });
+        } while (!a1.isStarted());
+
+        // Time between pause and resume: totalDuration
+        long entireSpan = totalDuration * 2;
+        long frameDelta = l1.lastUpdateTime - l1.firstRunningFrameTime;
+        assertTrue(Math.abs(entireSpan - frameDelta) < TOLERANCE);
+    }
+
+    @SmallTest
+    public void testEnd() throws Throwable {
+        final MyListener l1 = new MyListener();
+        final MyListener l2 = new MyListener();
+        a1.addListener(l1);
+        a2.addListener(l2);
+        a1.addListener(new MyListener() {
+            @Override
+            public void onAnimationEnd(Animator anim) {
+                anim.cancel();
+            }
+        });
+        a2.addListener(new MyListener() {
+            @Override
+            public void onAnimationCancel(Animator anim) {
+                anim.end();
+            }
+        });
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.cancelCalled);
+                assertFalse(l1.endCalled);
+                assertFalse(l2.cancelCalled);
+                assertFalse(l2.endCalled);
+                a1.start();
+                a2.start();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.end();
+                a2.cancel();
+            }
+        });
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Calling cancel from onAnimationEnd will be ignored.
+                assertFalse(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+                assertTrue(l2.cancelCalled);
+                assertTrue(l2.endCalled);
+
+                float value1 = (Float) a1.getAnimatedValue();
+                int value2 = (Integer) a2.getAnimatedValue();
+                assertEquals(A1_END_VALUE, value1);
+                assertEquals(A2_END_VALUE, value2);
+            }
+        });
+
+    }
+
+    @SmallTest
+    public void testEndValue() throws Throwable {
+        final MyListener l1 = new MyListener();
+        a1.addListener(l1);
+
+        final MyListener l2 = new MyListener();
+        a2.addListener(l2);
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.start();
+                a2.start();
+            }
+        });
+
+        Thread.sleep(POLL_INTERVAL);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                // Animation has started but not finished, check animated values against end values
+                assertFalse(l1.endCalled);
+                assertFalse(l2.endCalled);
+                assertNotEqual(A1_END_VALUE, a1.getAnimatedValue());
+                assertNotEqual(A1_END_VALUE, a2.getAnimatedValue());
+
+                // Force a2 to end.
+                a2.end();
+            }
+        });
+
+        Thread.sleep(a1.getTotalDuration());
+
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertFalse(l1.cancelCalled);
+                assertTrue(l1.endCalled);
+                assertFalse(l2.cancelCalled);
+                assertTrue(l2.endCalled);
+
+                // By now a1 should have finished normally and a2 has skipped to the end, check
+                // their end values.
+                assertEquals(A1_END_VALUE, ((Float) (a1.getAnimatedValue())).floatValue());
+                assertEquals(A2_END_VALUE, ((Integer) (a2.getAnimatedValue())).intValue());
+            }
+        });
+    }
+
+    @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) {
+            lastUpdateTime = SystemClock.uptimeMillis();
+            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
+        public void onAnimationCancel(Animator animation) {
+            cancelCalled = true;
+        }
+
+        @Override
+        public void onAnimationRepeat(Animator animation) {
+
+        }
+    }
+
+    class MyPauseListener implements Animator.AnimatorPauseListener {
+        boolean pauseCalled = false;
+        boolean resumeCalled = false;
+
+        @Override
+        public void onAnimationPause(Animator animation) {
+            pauseCalled = true;
+        }
+
+        @Override
+        public void onAnimationResume(Animator animation) {
+            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/app/backup/FullBackupTest.java b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
index 8c9c63c..c3afbf6 100644
--- a/core/tests/coretests/src/android/app/backup/FullBackupTest.java
+++ b/core/tests/coretests/src/android/app/backup/FullBackupTest.java
@@ -114,12 +114,14 @@
     public void testparseBackupSchemeFromXml_lotsOfIncludesAndExcludes() throws Exception {
         mXpp.setInput(new StringReader(
                 "<full-backup-content>" +
-                        "<exclude path=\"exclude1.txt\" domain=\"file\"/>" +
+                         "<exclude path=\"exclude1.txt\" domain=\"file\"/>" +
                         "<include path=\"include1.txt\" domain=\"file\"/>" +
                          "<exclude path=\"exclude2.txt\" domain=\"database\"/>" +
                         "<include path=\"include2.txt\" domain=\"database\"/>" +
-                         "<exclude path=\"exclude3.txt\" domain=\"sharedpref\"/>" +
-                        "<include path=\"include3.txt\" domain=\"sharedpref\"/>" +
+                         "<exclude path=\"exclude3\" domain=\"sharedpref\"/>" +
+                        "<include path=\"include3\" domain=\"sharedpref\"/>" +
+                         "<exclude path=\"exclude4.xml\" domain=\"sharedpref\"/>" +
+                        "<include path=\"include4.xml\" domain=\"sharedpref\"/>" +
                 "</full-backup-content>"));
 
 
@@ -146,16 +148,27 @@
                                 "include2.txt-journal")
                                 .getCanonicalPath()));
 
-        Set<String> sharedPrefDomainIncludes = includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN);
+        List<String> sharedPrefDomainIncludes = new ArrayList<String>(
+                includeMap.get(FullBackup.SHAREDPREFS_TREE_TOKEN));
+        Collections.sort(sharedPrefDomainIncludes);
+
         assertEquals("Didn't find expected sharedpref domain include.",
-                1, sharedPrefDomainIncludes.size());
+                3, sharedPrefDomainIncludes.size());
         assertEquals("Invalid path parsed for <include/>",
-                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3.txt")
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3")
                         .getCanonicalPath(),
-                sharedPrefDomainIncludes.iterator().next());
+                sharedPrefDomainIncludes.get(0));
+        assertEquals("Invalid path parsed for <include/>",
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include3.xml")
+                        .getCanonicalPath(),
+                sharedPrefDomainIncludes.get(1));
+        assertEquals("Invalid path parsed for <include/>",
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "include4.xml")
+                        .getCanonicalPath(),
+                sharedPrefDomainIncludes.get(2));
 
 
-        assertEquals("Unexpected number of <exclude/>s", 4, excludesSet.size());
+        assertEquals("Unexpected number of <exclude/>s", 6, excludesSet.size());
         // Sets are annoying to iterate over b/c order isn't enforced - convert to an array and
         // sort lexicographically.
         List<String> arrayedSet = new ArrayList<String>(excludesSet);
@@ -173,9 +186,17 @@
                 new File(mContext.getFilesDir(), "exclude1.txt").getCanonicalPath(),
                 arrayedSet.get(2));
         assertEquals("Invalid path parsed for <exclude/>",
-                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.txt")
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3")
                         .getCanonicalPath(),
                 arrayedSet.get(3));
+        assertEquals("Invalid path parsed for <exclude/>",
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude3.xml")
+                        .getCanonicalPath(),
+                arrayedSet.get(4));
+        assertEquals("Invalid path parsed for <exclude/>",
+                new File(mContext.getSharedPrefsFile("foo").getParentFile(), "exclude4.xml")
+                        .getCanonicalPath(),
+                arrayedSet.get(5));
     }
 
     public void testParseBackupSchemeFromXml_invalidXmlFails() throws Exception {
diff --git a/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
new file mode 100644
index 0000000..80181cf
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/AppsQueryHelperTests.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.content.pm;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.UserHandle;
+import android.test.AndroidTestCase;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+
+public class AppsQueryHelperTests extends AndroidTestCase {
+
+    private AppsQueryHelper mAppsQueryHelper;
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        mAppsQueryHelper = new AppsQueryHelperTestable(getContext());
+    }
+
+    public void testQueryAppsSystemAppsOnly() {
+        List<String> apps = mAppsQueryHelper.queryApps(0, true, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app2", "sys_app3"), apps);
+
+        apps = mAppsQueryHelper.queryApps(0, false, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app2", "sys_app3", "app4"), apps);
+    }
+
+    public void testQueryAppsNonLaunchable() {
+        List<String> apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS,
+                true, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
+
+        apps = mAppsQueryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS,
+                false, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
+    }
+
+    public void testQueryAppsInteractAcrossUser() {
+        List<String> apps = mAppsQueryHelper.queryApps(
+                AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM, true, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);
+
+        apps = mAppsQueryHelper.queryApps(
+                AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM, false, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1"), apps);
+    }
+
+    public void testQueryApps() {
+        List<String> apps = mAppsQueryHelper.queryApps(
+                AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
+                        |AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM,
+                true, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
+
+        apps = mAppsQueryHelper.queryApps(
+                AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
+                        |AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM,
+                false, UserHandle.SYSTEM);
+        assertEqualsIgnoreOrder(Arrays.asList("sys_app1", "sys_app3"), apps);
+    }
+
+    private class AppsQueryHelperTestable extends AppsQueryHelper {
+
+        public AppsQueryHelperTestable(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected List<ApplicationInfo> getAllApps(int userId) {
+            final ApplicationInfo ai1 = new ApplicationInfo();
+            ai1.flags |= ApplicationInfo.FLAG_SYSTEM;
+            ai1.packageName = "sys_app1";
+            final ApplicationInfo ai2 = new ApplicationInfo();
+            ai2.flags |= ApplicationInfo.FLAG_SYSTEM;
+            ai2.packageName = "sys_app2";
+            ai2.flags |= ApplicationInfo.FLAG_SYSTEM;
+            final ApplicationInfo ai3 = new ApplicationInfo();
+            ai3.packageName = "sys_app3";
+            ai3.flags |= ApplicationInfo.FLAG_SYSTEM;
+            final ApplicationInfo ai4 = new ApplicationInfo();
+            ai4.packageName = "app4";
+            return Arrays.asList(ai1, ai2, ai3, ai4);
+        }
+
+        @Override
+        protected List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, int userId) {
+            assertEquals(Intent.CATEGORY_LAUNCHER, intent.getCategories().iterator().next());
+            final ResolveInfo r2 = new ResolveInfo();
+            r2.activityInfo = new ActivityInfo();
+            r2.activityInfo.packageName = "sys_app2";
+            r2.activityInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+            final ResolveInfo r4 = new ResolveInfo();
+            r4.activityInfo = new ActivityInfo();
+            r4.activityInfo.packageName = "app4";
+            return Arrays.asList(r2, r4);
+        }
+
+        @Override
+        protected List<PackageInfo> getPackagesHoldingPermission(String perm, int userId) {
+            final PackageInfo p1 = new PackageInfo();
+            p1.packageName = "sys_app1";
+            p1.applicationInfo = new ApplicationInfo();
+            p1.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+            return Arrays.asList(p1);
+        }
+    }
+
+    private static void assertEqualsIgnoreOrder(List<String> expected, List<String> actual) {
+        assertTrue("Lists not equal. Expected " + expected + " but was " + actual,
+                (expected.size() == actual.size())
+                        && (new HashSet<>(expected).equals(new HashSet<>(actual))));
+    }
+}
diff --git a/core/tests/coretests/src/android/text/format/FormatterTest.java b/core/tests/coretests/src/android/text/format/FormatterTest.java
index d2e2131..be6e7ea 100644
--- a/core/tests/coretests/src/android/text/format/FormatterTest.java
+++ b/core/tests/coretests/src/android/text/format/FormatterTest.java
@@ -56,14 +56,14 @@
     public void testFormatBytes() {
         setLocale(Locale.ENGLISH);
 
-        checkFormatBytes(0, true, "0.00", 0);
-        checkFormatBytes(0, false, "0.00", 0);
+        checkFormatBytes(0, true, "0", 0);
+        checkFormatBytes(0, false, "0", 0);
 
-        checkFormatBytes(1, true, "1.0", 1);
-        checkFormatBytes(1, false, "1.00", 1);
+        checkFormatBytes(1, true, "1", 1);
+        checkFormatBytes(1, false, "1", 1);
 
         checkFormatBytes(12, true, "12", 12);
-        checkFormatBytes(12, false, "12.00", 12);
+        checkFormatBytes(12, false, "12", 12);
 
         checkFormatBytes(123, true, "123", 123);
         checkFormatBytes(123, false, "123", 123);
@@ -80,13 +80,15 @@
         checkFormatBytes(9123000, true, "8.7", 9122611);
         checkFormatBytes(9123000, false, "8.70", 9122611);
 
-        // The method doesn't really support negative values, but apparently people pass -1...
-        checkFormatBytes(-1, true, "-1.00", -1);
-        checkFormatBytes(-1, false, "-1.00", -1);
+        checkFormatBytes(-1, true, "-1", -1);
+        checkFormatBytes(-1, false, "-1", -1);
+
+        checkFormatBytes(-912, true, "-0.89", -911);
+        checkFormatBytes(-912, false, "-0.89", -911);
 
         // Missing FLAG_CALCULATE_ROUNDED case.
         BytesResult r = Formatter.formatBytes(getContext().getResources(), 1, 0);
-        assertEquals("1.00", r.value);
+        assertEquals("1", r.value);
         assertEquals(0, r.roundedBytes); // Didn't pass FLAG_CALCULATE_ROUNDED
 
         // Make sure it works on different locales.
diff --git a/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
new file mode 100644
index 0000000..e5d5542
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/SuggestionsPopupWindowTest.java
@@ -0,0 +1,117 @@
+/*
+ * 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.app.Activity;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.Spanned;
+import android.text.TextPaint;
+import android.text.style.SuggestionSpan;
+import android.text.style.TextAppearanceSpan;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * SuggestionsPopupWindowTest tests.
+ */
+public class SuggestionsPopupWindowTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
+
+    public SuggestionsPopupWindowTest() {
+        super(TextViewActivity.class);
+    }
+
+    @SmallTest
+    public void testTextAndAppearanceInSuggestionsPopup() {
+        final Activity activity = getActivity();
+
+        final String sampleText = "abc def ghi";
+        final String[] candidate = {"DEF", "Def"};
+        final SuggestionSpan suggestionSpan = new SuggestionSpan(activity, candidate,
+                SuggestionSpan.FLAG_AUTO_CORRECTION);
+        final int spanStart = 4;
+        final int spanEnd = 7;
+        TextAppearanceSpan expectedSpan = new TextAppearanceSpan(activity,
+                android.R.style.TextAppearance_SuggestionHighlight);
+        TextPaint tmpTp = new TextPaint();
+        expectedSpan.updateDrawState(tmpTp);
+        final int expectedHighlightTextColor = tmpTp.getColor();
+        final float expectedHighlightTextSize = tmpTp.getTextSize();
+
+        // Create and wait until SuggestionsPopupWindow is shown.
+        final EditText editText = (EditText) activity.findViewById(R.id.textview);
+        final Editor editor = editText.getEditorForTesting();
+        assertNotNull(editor);
+        activity.runOnUiThread(new Runnable() {
+            public void run() {
+                SpannableStringBuilder ssb = new SpannableStringBuilder();
+                ssb.append(sampleText);
+                ssb.setSpan(suggestionSpan, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_INCLUSIVE);
+                editText.setText(ssb);
+
+                Selection.setSelection(editText.getText(), spanStart, spanEnd);
+                editText.onTextContextMenuItem(TextView.ID_REPLACE);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
+
+        // In this test, the SuggestionsPopupWindow looks like
+        // abc def ghi
+        //   ----------
+        //   | *DEF*  |
+        //   | *Def*  |
+        //   | DELETE |
+        //   ----------
+        // *XX* means that XX is highlighted.
+        activity.runOnUiThread(new Runnable() {
+            public void run() {
+                Editor.SuggestionsPopupWindow popupWindow =
+                        editor.getSuggestionsPopupWindowForTesting();
+                assertNotNull(popupWindow);
+
+                ListView listView = (ListView) popupWindow.getContentViewForTesting();
+                assertNotNull(listView);
+
+                int childNum = listView.getChildCount();
+                // +1 for "DELETE" command.
+                assertEquals(candidate.length + 1, childNum);
+
+                for (int i = 0; i < candidate.length; ++i) {
+                    TextView textView = (TextView) listView.getChildAt(i);
+                    assertNotNull(textView);
+
+                    Spanned spanned = (Spanned) textView.getText();
+                    assertNotNull(spanned);
+
+                    // Check that the suggestion item order is kept.
+                    assertEquals(candidate[i], spanned.toString());
+
+                    // Check that the text is highlighted with correct color and text size.
+                    TextAppearanceSpan[] taSpan = spanned.getSpans(0, candidate[i].length(),
+                            TextAppearanceSpan.class);
+                    assertEquals(1, taSpan.length);
+                    TextPaint tp = new TextPaint();
+                    taSpan[0].updateDrawState(tp);
+                    assertEquals(expectedHighlightTextColor, tp.getColor());
+                    assertEquals(expectedHighlightTextSize, tp.getTextSize());
+                }
+            }
+        });
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/TextViewTest.java b/core/tests/coretests/src/android/widget/TextViewTest.java
index 0b94f8b..49d9115 100644
--- a/core/tests/coretests/src/android/widget/TextViewTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewTest.java
@@ -18,7 +18,7 @@
 
 import android.app.Activity;
 import android.content.Intent;
-import android.test.AndroidTestCase;
+import android.test.ActivityInstrumentationTestCase2;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.text.GetChars;
 import android.text.Selection;
@@ -27,11 +27,15 @@
 /**
  * TextViewTest tests {@link TextView}.
  */
-public class TextViewTest extends AndroidTestCase {
+public class TextViewTest extends ActivityInstrumentationTestCase2<TextViewActivity> {
+
+    public TextViewTest() {
+        super(TextViewActivity.class);
+    }
 
     @SmallTest
     public void testArray() throws Exception {
-        TextView tv = new TextView(mContext);
+        TextView tv = new TextView(getActivity());
 
         char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
                                 'W', 'o', 'r', 'l', 'd', '!' };
@@ -59,25 +63,34 @@
         assertEquals('\0', c2[5]);
     }
 
+    @SmallTest
     public void testProcessTextActivityResultNonEditable() {
-        TextView tv = new TextView(mContext);
+        final TextView tv = new TextView(getActivity());
         CharSequence originalText = "This is some text.";
         tv.setText(originalText, TextView.BufferType.SPANNABLE);
         assertEquals(originalText, tv.getText().toString());
         tv.setTextIsSelectable(true);
         Selection.setSelection((Spannable) tv.getText(), 0, tv.getText().length());
 
-        CharSequence newText = "Text is replaced.";
-        Intent data = new Intent();
-        data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
-        tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+        // We need to run this in the UI thread, as it will create a Toast.
+        getActivity().runOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                CharSequence newText = "Text is replaced.";
+                Intent data = new Intent();
+                data.putExtra(Intent.EXTRA_PROCESS_TEXT, newText);
+                tv.onActivityResult(TextView.PROCESS_TEXT_REQUEST_CODE, Activity.RESULT_OK, data);
+            }
+        });
+        getInstrumentation().waitForIdleSync();
 
         // This is a TextView, which can't be modified. Hence no change should have been made.
         assertEquals(originalText, tv.getText().toString());
     }
 
+    @SmallTest
     public void testProcessTextActivityResultEditable() {
-        EditText tv = new EditText(mContext);
+        EditText tv = new EditText(getActivity());
         CharSequence originalText = "This is some text.";
         tv.setText(originalText, TextView.BufferType.SPANNABLE);
         assertEquals(originalText, tv.getText().toString());
@@ -92,8 +105,9 @@
         assertEquals(newText, tv.getText().toString());
     }
 
+    @SmallTest
     public void testProcessTextActivityResultCancel() {
-        EditText tv = new EditText(mContext);
+        EditText tv = new EditText(getActivity());
         CharSequence originalText = "This is some text.";
         tv.setText(originalText, TextView.BufferType.SPANNABLE);
         assertEquals(originalText, tv.getText().toString());
@@ -108,8 +122,9 @@
         assertEquals(originalText, tv.getText().toString());
     }
 
+    @SmallTest
     public void testProcessTextActivityNoData() {
-        EditText tv = new EditText(mContext);
+        EditText tv = new EditText(getActivity());
         CharSequence originalText = "This is some text.";
         tv.setText(originalText, TextView.BufferType.SPANNABLE);
         assertEquals(originalText, tv.getText().toString());
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 350310c..27c6620 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -143,4 +143,7 @@
          access while in power save mode, even if they aren't in the foreground. -->
     <allow-in-power-save-except-idle package="com.android.providers.downloads" />
 
+    <!-- These are the packages that shouldn't run as system user -->
+    <system-user-blacklisted-app package="com.android.wallpaper.livepicker" />
+    <system-user-blacklisted-app package="com.android.settings" />
 </permissions>
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/images/training/auto-desktop-head-unit-context-menu-enabled.png b/docs/html/images/training/auto-desktop-head-unit-context-menu-enabled.png
new file mode 100644
index 0000000..99e60e9
--- /dev/null
+++ b/docs/html/images/training/auto-desktop-head-unit-context-menu-enabled.png
Binary files differ
diff --git a/docs/html/images/training/auto-desktop-head-unit-launch.png b/docs/html/images/training/auto-desktop-head-unit-launch.png
new file mode 100644
index 0000000..012857a4
--- /dev/null
+++ b/docs/html/images/training/auto-desktop-head-unit-launch.png
Binary files differ
diff --git a/docs/html/images/training/auto-desktop-head-unit-server-running.png b/docs/html/images/training/auto-desktop-head-unit-server-running.png
new file mode 100644
index 0000000..5aa3b83
--- /dev/null
+++ b/docs/html/images/training/auto-desktop-head-unit-server-running.png
Binary files differ
diff --git a/docs/html/images/training/auto-desktop-head-unit-wkst-launch.png b/docs/html/images/training/auto-desktop-head-unit-wkst-launch.png
new file mode 100644
index 0000000..4d48ac4
--- /dev/null
+++ b/docs/html/images/training/auto-desktop-head-unit-wkst-launch.png
Binary files differ
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/docs/html/preview/features/runtime-permissions.jd b/docs/html/preview/features/runtime-permissions.jd
index 8ab7619..62e49b9 100644
--- a/docs/html/preview/features/runtime-permissions.jd
+++ b/docs/html/preview/features/runtime-permissions.jd
@@ -916,8 +916,11 @@
   </dt>
 
   <dd>
-    Returns <code>true</code> if the app has the specified permission, whether
-    or not the device is using the M Preview.
+    Returns {@link android.content.pm.PackageManager#PERMISSION_GRANTED
+    PERMISSION_GRANTED} if the app has the specified permission, whether
+    or not the device is using the M Preview. If the app does not have the
+    specified permission, returns {@link
+    android.content.pm.PackageManager#PERMISSION_DENIED PERMISSION_DENIED}.
   </dd>
 
   <dt>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index dbc0f35..39822e5 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,28 +5,28 @@
 header.hide=1
 page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
 
-studio.version=1.3.1.0
+studio.version=1.3.2.0
 
-studio.linux_bundle_download=android-studio-ide-141.2135290-linux.zip
-studio.linux_bundle_bytes=351992670
-studio.linux_bundle_checksum=51e5f5de2b82883d87f85ee38cf7b7b8b2e7debf
+studio.linux_bundle_download=android-studio-ide-141.2178183-linux.zip
+studio.linux_bundle_bytes=352010593
+studio.linux_bundle_checksum=cf780413f8c8223eb348bd27c19a9c04b75eaeb2
 
-studio.mac_bundle_download=android-studio-ide-141.2135290-mac.dmg
-studio.mac_bundle_bytes=368321249
-studio.mac_bundle_checksum=9fc12b5657ff52c761b7e7c115feade2a9728386
+studio.mac_bundle_download=android-studio-ide-141.2178183-mac.dmg
+studio.mac_bundle_bytes=368335367
+studio.mac_bundle_checksum=75b67eb15a34a152a40e7189484ab0ebc375b877
 
-studio.win_bundle_download=android-studio-ide-141.2135290-windows.zip
-studio.win_bundle_bytes=344406793
-studio.win_bundle_checksum=3b4c4924cb9495e56db61ca0e8c8d2bf588c4b97
+studio.win_bundle_download=android-studio-ide-141.2178183-windows.zip
+studio.win_bundle_bytes=344424713
+studio.win_bundle_checksum=3134f226b5f3c3f74d4fc2d9cff03a4458f01d69
 
 
-studio.win_bundle_exe_download=android-studio-bundle-141.2135290-windows.exe
-studio.win_bundle_exe_bytes=1008506096
-studio.win_bundle_exe_checksum=8cff590f2e08e339f8c2491b287a840ae87c7383
+studio.win_bundle_exe_download=android-studio-bundle-141.2178183-windows.exe
+studio.win_bundle_exe_bytes=1136982712
+studio.win_bundle_exe_checksum=c7d39c529dd434489da9d086ff689d34dc791526
 
-studio.win_notools_exe_download=android-studio-ide-141.2135290-windows.exe
-studio.win_notools_exe_bytes=321791312
-studio.win_notools_exe_checksum=d70fb49d03db9dded19c891a92452601e39272f4
+studio.win_notools_exe_download=android-studio-ide-141.2178183-windows.exe
+studio.win_notools_exe_bytes=321810248
+studio.win_notools_exe_checksum=b5d1aaa000729c03a3cf980add79d1b93121c56d
 
 
 
@@ -289,7 +289,7 @@
 </ul>
 
 <a class="online landing-button green download-bundle-button"
-href="#Other" >Download Android Studio</a>
+href="#Other" >Download Android Studio<br/><span class='small'></span></a>
 
 <!-- this appears when viewing the offline docs -->
 <p class="offline">
diff --git a/docs/html/tools/help/desktop-head-unit.jd b/docs/html/tools/help/desktop-head-unit.jd
new file mode 100644
index 0000000..981979c
--- /dev/null
+++ b/docs/html/tools/help/desktop-head-unit.jd
@@ -0,0 +1,439 @@
+page.title=Desktop Head Unit
+page.tags="auto", "car", "testing","dhu"
+@jd:body
+
+
+<div id="qv-wrapper">
+<div id="qv">
+
+    <h2>In this document</h2>
+    <ol>
+      <li><a href="#launching-dhu">Launching the DHU</a></li>
+      <li><a href="#dhu-commands">Issuing DHU Commands</a></li>
+    </ol>
+
+  <h2>See also</h2>
+  <ol>
+    <li><a href="{@docRoot}training/auto/start/index.html#test-it-dhu">Run and Test Auto Apps</a></li>
+  </ol>
+
+</div>
+</div>
+
+
+<p>The Desktop Head Unit (DHU) enables your development machine to emulate an Android Auto
+head unit, so you can easily run and test Android Auto apps. The DHU runs on
+Windows, Mac, and Linux hosts and replaces previous Android Auto simulators,
+such as the Android Media Browser and Messaging
+simulators.</p>
+
+<p class="note"><strong>Note:</strong> For other information about testing Auto apps, see the
+training lesson
+<a href="{@docRoot}training/auto/start/index.html#test-it-dhu">Run and Test Auto Apps</a>.  </p>
+
+
+<h2 id="launching-dhu">Launching the DHU</h2>
+
+<p>
+  To launch the DHU, run the <code>desktop-head-unit.exe</code> (on Windows)
+  or <code>desktop-head-unit</code> (on Mac or Linux) command, as described in
+  <a href="{@docRoot}training/auto/start/index.html#connecting-dhu">Connecting
+  the DHU to your mobile device</a>.
+</p>
+
+<p>
+  By default, the DHU emulates the most common form of Android Auto-compatible
+  head unit, which uses a touch screen user interface. You can simulate user
+  touches by clicking the DHU with a mouse. To emulate head units which use
+  a rotary controller for input, you can use the <code>-i controller</code> flag,
+  as in this example:
+</p>
+
+<pre class="no-pretty-print">$ ./desktop-head-unit -i controller</pre>
+
+<p>
+  When the DHU is in rotary-controller mode you can simulate controller
+  operations by using keyboard shortcuts, as described in <a href=
+  "#cmd-bindings">DHU commands and key bindings</a>. If the DHU is in rotary
+  controller mode, it ignores mouse clicks; you must operate Android Auto with
+  the simulated rotary controller operations.
+</p>
+
+<h2 id="dhu-commands">Issuing DHU Commands</h2>
+
+<p>
+  DHU commands allow you to test your app with Android Auto features, such as
+  playing voice input or switching between night and day display mode. You can issue commands to
+  the DHU by running commands from the terminal window where you launched DHU.
+  You can also issue commands by selecting the DHU window and
+  using keyboard shortcuts. The DHU commands
+  and key bindings for all controls are listed in <a href="#cmd-bindings">DHU
+  commands and key bindings</a>.
+</p>
+
+
+<h3 id="day-night">Switching between day and night mode</h3>
+
+<p>
+  Android Auto supports different color schemes for day and night. You should test your app in both
+  day and night mode. You can switch between night and day mode in either of the
+  following ways:
+</p>
+
+<ul>
+  <li>Run the command <code>daynight</code> in the terminal where you launched the DHU.
+  </li>
+
+  <li>Select the DHU window and press the <strong>N</strong> key.
+  </li>
+</ul>
+
+<h3>Microphone testing</h3>
+
+<p>The DHU supports using a microphone for voice input. You can also instruct the DHU to treat
+a pre-recorded voice track as input, as if the DHU had heard the track through the microphone.</p>
+
+<p>To use a pre-recorded sound file as input, enter this command: </p>
+<pre class="no-pretty-print">
+$ mic play &lt;sound_file_path&gt;/&lt;sound_file&gt;.wav
+</pre>
+
+<p>For your convenience, we have provided the following sound files for common
+voice commands. These sound files are installed in the
+<code>&lt;sdk&gt;/extras/google/auto/voice/</code> directory.</p>
+
+<dl>
+  <dt>
+    <code>exitnav.wav</code>
+  </dt>
+
+  <dd>
+    "Exit navigation."
+  </dd>
+
+  <dt>
+    <code>navgoogle.wav</code>
+  </dt>
+
+  <dd>
+    "Navigate to 1600 Amphitheatre Parkway, Mountain View."
+  </dd>
+
+  <dt>
+    <code>navsoh.wav</code>
+  </dt>
+
+  <dd>
+    "Navigate to Sydney Opera House."
+  </dd>
+
+  <dt>
+    <code>nextturn.wav</code>
+  </dt>
+
+  <dd>
+    "When is my next turn?"
+  </dd>
+
+  <dt>
+    <code>showalternateroute.wav</code>
+  </dt>
+
+  <dd>
+    "Show alternate routes.""
+  </dd>
+
+  <dt>
+    <code>howlong.wav</code>
+  </dt>
+
+  <dd>
+    "How long until I get there?"
+  </dd>
+
+  <dt>
+    <code>navhome.wav</code>
+  </dt>
+
+  <dd>
+    "Navigate to home."
+  </dd>
+
+  <dt>
+    <code>navwork.wav</code>
+  </dt>
+
+  <dd>
+    "Navigate to work.""
+  </dd>
+
+  <dt>
+    <code>pause.wav</code>
+  </dt>
+
+  <dd>
+    "Pause music."
+  </dd>
+
+  <dt>
+    <code>showtraffic.wav</code>
+  </dt>
+
+  <dd>
+    "Show traffic."
+  </dd>
+</dl>
+<h3 id="cmd-bindings">DHU commands and key bindings</h3>
+
+<p>The DHU supports the following commands.</p>
+
+<p class="table-caption" id="table-commands"><strong>Table 1.</strong> Commands and key bindings</p>
+<table>
+<tr>
+  <th>Category</th>
+  <th>Command</th>
+  <th>Subcommand</th>
+  <th>Argument(s)</th>
+  <th>Keyboard Shortcut(s)</th>
+  <th>Description</th>
+</tr>
+
+<!--system-->
+
+<tr>
+<td rowspan="4">System</td>
+<td>help</td>
+<td></td>
+<td>[command]</td>
+<td></td>
+<td>Shows the full command set. Specifying a command name (for example, <code>help day</code>)
+  causes the system to show help for that command.</td>
+</tr>
+
+<tr>
+
+<td>quit</td>
+<td></td>
+<td></td>
+<td>Alt+q</td>
+<td>Quits the head unit.</td>
+</tr>
+
+<tr>
+
+<td>sleep</td>
+<td></td>
+<td>[seconds]</td>
+<td></td>
+<td>Sleeps for one second. Specifying an argument (for example, <code>sleep 30</code>) causes the
+system to sleep the specified number of seconds. This command
+is useful if you are writing scripts for the DHU. (You can run a script by using I/O redirection
+from the command line: <code>./desktop-head-unit &lt; script.txt</code> loads commands from the
+file <code>script.txt</code>.)</td>
+</tr>
+
+<tr>
+
+<td>screenshot</td>
+<td></td>
+<td>filename.png</td>
+<td></td>
+<td>Saves a screenshot to <code>filename.png</code>.</td>
+</tr>
+
+
+<!--microphone-->
+
+<tr>
+<td rowspan="3">Microphone</td>
+<td rowspan="3">mic</td>
+<td>begin</td>
+<td></td>
+<td>m </td>
+<td>Activates the microphone (equivalent to clicking the steering wheel's microphone button) and
+waits for input from the computer microphone.</td>
+</tr>
+
+<tr>
+
+
+<td>play</td>
+<td>filename.wav</td>
+<td></td>
+<td>Causes the DHU to treat <code>filename.wav</code> as voice input, as if it had heard that sound
+  through the microphone. You do not hear the sound file being played, but you do hear
+  the response from Android Auto.</td>
+</tr>
+
+<tr>
+
+
+<td>repeat</td>
+<td></td>
+<td></td>
+<td>Repeats the last <code>mic play</code> command, as if you had called <code>mic play</code>
+  again with the same sound file parameter.</td>
+</tr>
+
+<!--Input-->
+
+<tr>
+<td rowspan="7">Input</td>
+<td rowspan="6">dpad</td>
+<td>up <br> down <br> left <br> right</td>
+<td></td>
+<td>Arrow keys</td>
+<td>Simulates moving the rotary controller.</td>
+</tr>
+
+<tr>
+
+
+<td>soft left <br> soft right</td>
+<td></td>
+<td>Shift+Arrow keys</td>
+<td>Simulates pressing the side buttons available on some rotary controllers.</td>
+</tr>
+
+<tr>
+
+
+<td>click</td>
+<td></td>
+<td>Return</td>
+<td>Simulates pressing the rotary controller.</td>
+</tr>
+
+<tr>
+
+
+<td>back</td>
+<td></td>
+<td>Backspace</td>
+<td>Simulates pressing the <strong>back</strong> button available below some rotary
+  controllers.</td>
+</tr>
+
+<tr>
+
+
+<td>rotate left <br> rotate right</td>
+<td></td>
+<td>1 <br> 2</td>
+<td>Simulates rotating the rotary controller left (counter-clockwise) or right (clockwise).</td>
+</tr>
+
+<tr>
+
+
+<td>flick left <br> flick right</td>
+<td></td>
+<td>Shift+1 <br> Shift+2</td>
+<td>Simulates a fast spin of the rotary controller to the left (counter-clockwise) or right
+  (clockwise).</td>
+</tr>
+
+<tr>
+
+<td>tap</td>
+<td></td>
+<td>x y</td>
+<td></td>
+<td>Simulates a touch event at the specified coordinates. For example, <code>tap 50 100</code></td>
+</tr>
+
+
+<!--Day/Night-->
+
+<tr>
+<td rowspan="3">Day/Night</td>
+<td>day</td>
+<td></td>
+<td></td>
+<td>Shift+n</td>
+<td>Activates day mode (high brightness, full color).</td>
+</tr>
+
+<tr>
+
+<td>night</td>
+<td></td>
+<td> </td>
+<td>Ctrl+n </td>
+<td>Activates night mode (low brightness, high contrast).</td>
+</tr>
+
+<tr>
+
+<td>daynight</td>
+<td></td>
+<td></td>
+<td>n </td>
+<td>Toggles current day/night mode.</td>
+</tr>
+
+</table>
+
+
+
+
+<h2 id="auto-simulators">Media Browser and Messaging Simulators</h2>
+
+<p class="caution"><strong>Important:</strong> Use of the Android Media Browser and Messaging
+Simulators for testing Android Auto apps is deprecated. Instead, we recommend using the
+Desktop Head Unit, which enables your development machine to act as if it were an Android Auto head
+unit.</p>
+
+<p>To get the simulators, open the
+<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> and download
+them from <strong>Extras &gt; Android Auto API Simulators</strong>.</p>
+
+<p>Before you begin testing, compile your app in your development environment.
+Install your app and the Android simulator for the features you want to test
+(that is, audio or messaging) on a physical or virtual device running Android
+5.0 (API level 21) or higher. To check the version of Android on the device, go
+to <strong>Settings &gt; About phone</strong> (or <strong>About tablet</strong>)
+<strong>&gt; Android Version</strong>.</p>
+
+<h3 id="testing-audio-apps">Testing audio apps</h3>
+<p>To run and test audio apps:</p>
+
+<ol>
+<li>Install the Android Media Browser simulator
+({@code &lt;sdk&gt;/extras/google/simulators/media-browser-simulator.apk}) on
+the test device. You can do this using
+the <a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li>
+<li>Enable <a href="{@docRoot}tools/device.html#developer-device-options">
+developer options</a> on the test device.</li>
+<li>Install your app on the test device.</li>
+<li>Launch the Android Media Browser simulator to see how your audio app
+appears in Auto. If your app does not appear, stop the simulator from
+<strong>Settings &gt; Apps</strong> and restart it.</li>
+</ol>
+
+
+<h3 id="testing-messaging-apps">Testing messaging apps</h3>
+<p>To run and test messaging apps:</p>
+
+<ol>
+<li>Install the Android Messaging simulator
+  ({@code &lt;sdk&gt;/extras/google/simulators/messaging-simulator.apk})
+on the test device. You can do this using the
+<a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li>
+<li>Enable the simulator to read notifications posted on the system:
+<ol type="a">
+	<li>Enable <a href="{@docRoot}tools/device.html#developer-device-options">
+developer options</a> on the test device.</li>
+  <li>Click <strong>Settings &gt; Sounds &amp; Notifications &gt; Notification
+    Access</strong> and check the box labeled
+    <strong>Messaging Simulator</strong>.</li>
+</ol>
+<li>Install your app on the test device.</li>
+<li>Launch the Android Messaging Simulator to see how your messaging app appears
+in Auto. If your app does not appear, stop the simulator from
+<strong>Settings &gt; Apps</strong> and restart it.</li>
+</ol>
+
+
+
+
diff --git a/docs/html/tools/help/monkey.jd b/docs/html/tools/help/monkey.jd
index 941f5d9..7c64830 100644
--- a/docs/html/tools/help/monkey.jd
+++ b/docs/html/tools/help/monkey.jd
@@ -130,7 +130,7 @@
 <td><code>--pct-majornav &lt;percent&gt;</code></td>
 <td>Adjust percentage of "major" navigation events.
 (These are navigation events that will typically cause actions within your UI, such as
-the center button in a 5-way pad, the back key, or the menu key.)</td>
+the center button in a 5-way pad or the menu key.)</td>
 </tr>
 
 <tr>
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index c922b28..298b173 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -43,6 +43,29 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>Android Studio v1.3.2</a> <em>(August 2015)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+    <p>Fixes and enhancements:</p>
+    <ul>
+      <li>Added support for Android 6.0 (API level 23), including new icons and AVD Manager
+        support for creating devices with new screen densities.</li>
+      <li>Fixed an exception that was occuring during update checks.
+        <a href="http://b.android.com/183068">Issue: 183068</a></li>
+      <li>Fixed problem where unresolved view coordinates could cause the layout editor to crash.
+        <a href="http://b.android.com/178690">Issue: 178690</a></li>
+      <li>Fixed issue with invalid resource type warnings.
+        <a href="http://b.android.com/182433">Issue: 182433</a></li>
+      <li>Fixed lint check that was incorrectly flagging resources as private.
+        <a href="http://b.android.com/183120">Issue: 183120</a></li>
+    </ul>
+  </div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>Android Studio v1.3.1</a> <em>(August 2015)</em>
   </p>
   <div class="toggle-content-toggleme">
@@ -60,8 +83,6 @@
 </div>
 
 
-
-
 <div class="toggle-content closed">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
@@ -100,7 +121,7 @@
       <li>Added <a href="{@docRoot}tools/data-binding/guide.html">data binding</a> support to
         create declarative layouts that bind your application logic to layout elements. </li>
       <li>Added support for a separate
-        <a href="{@docRoot}tools/studio/studio-features.html#test-module">test APK module</a> 
+        <a href="{@docRoot}tools/studio/studio-features.html#test-module">test APK module</a>
         to build test APKs in Android Studio.  </li>
       <li>Updated the <a href="{@docRoot}tools/help/avd-manager.html">AVD Manager</a> with HAXM
         optimizations and improved notifications. </li>
diff --git a/docs/html/tools/sdk/eclipse-adt.jd b/docs/html/tools/sdk/eclipse-adt.jd
index 08634da..3c12a64 100644
--- a/docs/html/tools/sdk/eclipse-adt.jd
+++ b/docs/html/tools/sdk/eclipse-adt.jd
@@ -53,6 +53,39 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+      alt=""/>ADT 23.0.7</a> <em>(August 2015)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+<dl>
+  <dt>Dependencies:</dt>
+
+  <dd>
+    <ul>
+      <li>Java 7 or higher is required if you are targeting Android 5.0 and higher.</li>
+      <li>Java 1.6 or higher is required if you are targeting other releases.</li>
+      <li>Eclipse Indigo (Version 3.7.2) or higher is required.</li>
+      <li>This version of ADT is designed for use with
+        <a href="{@docRoot}tools/sdk/tools-notes.html">SDK Tools r24.1.2</a>.
+        If you haven't already installed SDK Tools r24.1.2 into your SDK, use the
+        Android SDK Manager to do so.</li>
+    </ul>
+  </dd>
+
+  <dt>General Notes:</dt>
+  <dd>
+    <ul>
+        <li>Fixed issues with the rendering library for the visual layout editor.</li>
+    </ul>
+  </dd>
+</dl>
+</div>
+</div>
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
       alt=""/>ADT 23.0.6</a> <em>(March 2015)</em>
   </p>
 
@@ -75,7 +108,7 @@
   <dt>General Notes:</dt>
   <dd>
     <ul>
-        <li>Fixed issues with the rendering library.</li>
+        <li>Fixed issues with the rendering library for the visual layout editor.</li>
     </ul>
   </dd>
 </dl>
diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd
index b3af7a2..19f93e9 100644
--- a/docs/html/tools/support-library/features.jd
+++ b/docs/html/tools/support-library/features.jd
@@ -307,8 +307,8 @@
 on how to set up your project, follow the instructions in <a
 href="{@docRoot}tools/support-library/setup.html#libs-with-res">Adding libraries
 with resources</a>. If you are developing in Eclipse/ADT, make sure to include
-both the <code>android-support-v7-mediarouter.jar</code> and
-<code>android-support-v7-appcompat.jar</code> files.</p>
+the <code>android-support-v7-mediarouter.jar</code>, <code>android-support-v7-appcompat.jar</code>,
+and <code>android-support-v7-palette.jar</code> files.</p>
 
 <p>If you are using Android Studio, all you need to do is specify the Gradle build
 script dependency identifier <code>com.android.support:support-v7-mediarouter:&lt;revision&gt;</code>,
diff --git a/docs/html/tools/tools_toc.cs b/docs/html/tools/tools_toc.cs
index db19d4f..72f9f21 100644
--- a/docs/html/tools/tools_toc.cs
+++ b/docs/html/tools/tools_toc.cs
@@ -160,6 +160,7 @@
       <li><a href="<?cs var:toroot ?>tools/help/avd-manager.html">AVD Manager</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/bmgr.html">bmgr</a>
       <li><a href="<?cs var:toroot ?>tools/help/monitor.html">Device Monitor</a></li>
+      <li><a href="<?cs var:toroot ?>tools/help/desktop-head-unit.html">Desktop Head Unit</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/dmtracedump.html">dmtracedump</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/draw9patch.html">Draw 9-Patch</a></li>
       <li><a href="<?cs var:toroot ?>tools/help/emulator.html">Emulator</a></li>
diff --git a/docs/html/training/auto/start/index.jd b/docs/html/training/auto/start/index.jd
index 22e7521..f6cdbd1 100644
--- a/docs/html/training/auto/start/index.jd
+++ b/docs/html/training/auto/start/index.jd
@@ -16,7 +16,7 @@
   <ol>
     <li><a href="#dev-project">Set Up an Auto Project</a></li>
     <li><a href="#build-it">Build Auto Apps</a></li>
-    <li><a href="#test-it">Run and Test Auto Apps</a></li>
+    <li><a href="#test-it-dhu">Run and Test Auto Apps </a></li>
   </ol>
 
  <h2>You should also read</h2>
@@ -149,57 +149,124 @@
 more information, see
 <a href="{@docRoot}distribute/essentials/quality/auto.html">Auto App Quality</a>.</p>
 
-<h2 id="test-it">Run and Test Auto Apps</h2>
 
-<p>As you prepare to publish your app, make sure that your app looks correct
-when projected on the Auto user interface. Use the Android Media Browser
-simulator and Android Messaging simulators to view and test your audio or
-messaging apps in a screen that looks similar to what is projected on Auto.</p>
 
-<p>To get the simulators, open the
-<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> and download
-them from <strong>Extras &gt; Android Auto API Simulators</strong>.</p>
+<h2 id="test-it-dhu">Run and Test Auto Apps </h2>
 
-<p>Before you begin testing, compile your app in your development environment.
-Install your app and the Android simulator for the features you want to test
-(that is, audio or messaging) on a physical or virtual device running Android
-5.0 (API level 21) or higher. To check the version of Android on the device, go
-to <strong>Settings &gt; About &gt; Android Version</strong>.</p>
+<p>
+  As you develop, you can run and test your app on your development machine
+  using the <em>Desktop Head Unit</em> (DHU). The DHU replaces the existing
+  simulators and enables your development machine to simulate a vehicle
+  dashboard system running Android Auto.
+</p>
 
-<h3 id="testing-audio-apps">Testing audio apps</h3>
-<p>To run and test audio apps:</p>
+<h3 id="installing-dhu">Installing the DHU</h3>
 
 <ol>
-<li>Install the Android Media Browser simulator
-({@code &lt;sdk&gt;/extras/google/simulators/media-browser-simulator.apk}) on
-the test device. You can do this using
-the <a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li>
-<li>Enable <a href="{@docRoot}tools/device.html#device-developer-options">
-developer options</a> on the test device.</li>
-<li>Install your app on the test device.</li>
-<li>Launch the Android Media Browser simulator to see how your audio app
-appears in Auto. If your app does not appear, stop the simulator from
-<strong>Settings &gt; Apps</strong> then restart it.</li>
+  <li>Enable developer mode on your mobile device, as described in
+    <a href="{@docRoot}tools/device.html#developer-device-options">Enabling On-device
+    Developer Options</a>. </li>
+  <li>Compile your app in your development environment and install your app on
+    a physical mobile device running Android 5.0 (API level 21) or higher. To check the
+    version of Android on a Nexus device, go to
+    <strong>Settings &gt; About phone</strong> (or <strong>About tablet</strong>) <strong>&gt;
+    Android version</strong>.</li>
+
+  <li>Install the
+     <a class="external-link"
+     href="https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead&hl=en"
+     >Android Auto app</a> on the mobile device.</li>
+  <li>Open the <a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> and
+    download the DHU package <strong>Android Auto Desktop Head Unit</strong> from the
+    <em>SDK Tools</em> tab. The DHU installs in the <code>&lt;sdk&gt;/extras/google/auto/</code>
+    directory.</li>
+  <li>If you are running the DHU on Linux, you must also install
+    the portaudio, libpng, sdl2, and sdl2_ttf libraries.
+    The procedure to do this varies depending on your Linux distribution. For example, on
+    Debian-derived Linux distributions, you can install the libraries with this command:
+
+<pre class="no-pretty-print">
+$ sudo apt-get install libsdl2-2.0-0 libsdl2-ttf-2.0-0 libportaudio2 libpng12-0
+</pre>
+
+  </li>
 </ol>
 
-<h3 id="testing-messaging-apps">Testing messaging apps</h3>
-<p>To run and test messaging apps:</p>
+<div class="figure" style="width:330px">
+  <img src="{@docRoot}images/training/auto-desktop-head-unit-server-running.png"
+      alt="" >
+  <p class="img-caption">
+    <strong>Figure 2.</strong> Notification that the head unit server is running.
+  </p>
+</div>
+<img src="{@docRoot}images/training/auto-desktop-head-unit-context-menu-enabled.png"
+    alt="" >
+<p class="img-caption">
+  <strong>Figure 1.</strong> Context menu with developer options.
+</p>
+
+<h3 id="connecting-dhu">Connecting the DHU to your mobile device</h3>
+
+<p>Run the DHU by connecting your mobile device to a development machine and setting up a connection to
+  the head unit server over <a href="{@docRoot}tools/help/adb.html">Android Debug Bridge
+  (ADB)</a>. Follow these steps to set up tunneling and start the DHU:</p>
 
 <ol>
-<li>Install the Android Messaging simulator
-  ({@code &lt;sdk&gt;/extras/google/simulators/messaging-simulator.apk})
-on the test device. You can do this using the
-<a href="{@docRoot}tools/help/adb.html#move">adb</a> command line tool.</li>
-<li>Enable the simulator to read notifications posted on the system:
-<ol type="a">
-	<li>Enable <a href="{@docRoot}tools/device.html#device-developer-options">
-developer options</a> on the test device.</li>
-	<li>Click <strong>Settings &gt; Sounds &amp; Notifications &gt; Notification
-	Access</strong> and check the box labeled
-	<strong>Messaging Simulator</strong>.</li>
+  <li>On the mobile device, enable Android Auto developer mode by starting the Android Auto
+    companion app, and then tapping the header image 10 times.
+    This step is only required the first time you run the companion app.
+  </li>
+  <li>If the server is not already running, select <strong>Start head unit server</strong>
+     from the Android Auto menu.
+    <p>On the device, a foreground service appears in the notification area. </p>
+  </li>
+
+  <li>Connect the mobile device to the development machine via USB. Your device must be unlocked to
+    launch the DHU.
+  </li>
+  <li>On the development machine, run the following {@code adb} command to
+    forward socket connections from the
+    development machine's port 5277 to the same port number on the Android device.
+    This configuration allows the DHU to connect to the head unit server running on your phone over
+    a TCP socket.
+    <pre class="no-pretty-print">$ adb forward tcp:5277 tcp:5277</pre>
+  </li>
+
+  <li>Start the DHU by running the command <code>desktop-head-unit.exe</code> (on Windows)
+    or <code>./desktop-head-unit</code> (on Mac or Linux) from the
+    <code>&lt;sdk&gt;/extras/google/auto/</code> directory.
+
+<pre class="no-pretty-print">$ cd &lt;sdk&gt;/extras/google/auto
+$ ./desktop-head-unit</pre>
+
+    <p>
+      By default, the head unit server connects over port 5277. To override the host or port
+      (for example, to forward over SSH), use the <code>--adb</code> flag.
+    </p>
+
+  </li>
 </ol>
-<li>Install your app on the test device.</li>
-<li>Launch the Android Messaging Simulator to see how your messaging app appears
-in Auto. If your app does not appear, stop the simulator from
-<strong>Settings &gt; Apps</strong> then restart it.</li>
-</ol>
+
+<div class="figure" style="width:432px">
+
+    <img src="{@docRoot}images/training/auto-desktop-head-unit-wkst-launch.png"
+        alt="" >
+    <p class="img-caption">
+      <strong>Figure 4.</strong> DHU launches on the development machine.
+    </p>
+</div>
+
+    <img src="{@docRoot}images/training/auto-desktop-head-unit-launch.png"
+        alt="" >
+    <p class="img-caption">
+      <strong>Figure 3.</strong> Android Auto launches on the mobile device.
+    </p>
+
+<p>
+  After you set up and start the DHU, you can run DHU commands from the command line to run and
+  test your app from the terminal. You can also run these commands by using keyboard shortcuts. For
+  more information about DHU configuration and commands, see <a href=
+  "{@docRoot}tools/help/desktop-head-unit.html">Desktop Head Unit</a>.
+</p>
+
+
diff --git a/docs/html/training/wearables/watch-faces/index.jd b/docs/html/training/wearables/watch-faces/index.jd
index b544636..a329fda 100644
--- a/docs/html/training/wearables/watch-faces/index.jd
+++ b/docs/html/training/wearables/watch-faces/index.jd
@@ -66,7 +66,7 @@
 Showing Information in Watch Faces</a></dt>
 <dd>Learn how to incorporate contextual information into your watch face.</dd>
 <dt><a href="{@docRoot}training/wearables/watch-faces/interacting.html">
-Making Your Watch Face Interactive </a></dt>
+Creating Interactive Watch Faces</a></dt>
 <dd>Learn how to enable the user to interact with your watch face.</dd>
 <dt><a href="{@docRoot}training/wearables/watch-faces/configuration.html">
 Providing Configuration Activities</a></dt>
diff --git a/docs/html/training/wearables/watch-faces/interacting.jd b/docs/html/training/wearables/watch-faces/interacting.jd
index 4f2486c..5a44fde 100644
--- a/docs/html/training/wearables/watch-faces/interacting.jd
+++ b/docs/html/training/wearables/watch-faces/interacting.jd
@@ -62,10 +62,10 @@
 reserves gestures such as drag and long-press for system UI elements.
 Therefore, the system does not send raw touch events to the watch face. Instead, the system forwards specific commands to the
 <a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.Engine.html#onTapCommand(int, int, int, long)">
-method.
+onTapCommand()</a> method.
 
 <p>The system sends the first command,
-<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH"</a>
+<a href="{@docRoot}reference/android/support/wearable/watchface/WatchFaceService.html#TAP_TYPE_TOUCH">
 {@code TAP_TYPE_TOUCH}</a>, when the user initially touches the
 screen. This event lets you provide visual feedback to the user on touch.  Your app should not
 launch a UI when this event triggers. Launching a UI prevents drag events from opening the app
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index 0e9823d..91e704a 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -486,9 +486,9 @@
      */
     public enum Direction {
         /** clockwise */
-        CW  (1),    // must match enum in SkPath.h
+        CW  (0),    // must match enum in SkPath.h
         /** counter-clockwise */
-        CCW (2);    // must match enum in SkPath.h
+        CCW (1);    // must match enum in SkPath.h
 
         Direction(int ni) {
             nativeInt = ni;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 32af59a..b95c183 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -1146,77 +1146,11 @@
      * document, tries to create a Drawable from that tag. Returns {@code null}
      * if the tag is not a valid drawable.
      */
-    @SuppressWarnings("deprecation")
     public static Drawable createFromXmlInner(Resources r, XmlPullParser parser, AttributeSet attrs,
             Theme theme) throws XmlPullParserException, IOException {
-        final Drawable drawable;
-
-        final String name = parser.getName();
-        switch (name) {
-            case "selector":
-                drawable = new StateListDrawable();
-                break;
-            case "animated-selector":
-                drawable = new AnimatedStateListDrawable();
-                break;
-            case "level-list":
-                drawable = new LevelListDrawable();
-                break;
-            case "layer-list":
-                drawable = new LayerDrawable();
-                break;
-            case "transition":
-                drawable = new TransitionDrawable();
-                break;
-            case "ripple":
-                drawable = new RippleDrawable();
-                break;
-            case "color":
-                drawable = new ColorDrawable();
-                break;
-            case "shape":
-                drawable = new GradientDrawable();
-                break;
-            case "vector":
-                drawable = new VectorDrawable();
-                break;
-            case "animated-vector":
-                drawable = new AnimatedVectorDrawable();
-                break;
-            case "scale":
-                drawable = new ScaleDrawable();
-                break;
-            case "clip":
-                drawable = new ClipDrawable();
-                break;
-            case "rotate":
-                drawable = new RotateDrawable();
-                break;
-            case "animated-rotate":
-                drawable = new AnimatedRotateDrawable();
-                break;
-            case "animation-list":
-                drawable = new AnimationDrawable();
-                break;
-            case "inset":
-                drawable = new InsetDrawable();
-                break;
-            case "bitmap":
-                drawable = new BitmapDrawable();
-                break;
-            case "nine-patch":
-                drawable = new NinePatchDrawable();
-                break;
-            default:
-                throw new XmlPullParserException(parser.getPositionDescription() +
-                        ": invalid drawable tag " + name);
-
-        }
-        drawable.inflate(r, parser, attrs, theme);
-        return drawable;
+        return r.getDrawableInflater().inflateFromXml(parser.getName(), parser, attrs, theme);
     }
 
-
     /**
      * Create a drawable from file path name.
      */
diff --git a/graphics/java/android/graphics/drawable/DrawableInflater.java b/graphics/java/android/graphics/drawable/DrawableInflater.java
new file mode 100644
index 0000000..348af70d
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/DrawableInflater.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.DrawableRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+import android.view.InflateException;
+
+import java.io.IOException;
+import java.lang.reflect.Constructor;
+import java.util.HashMap;
+
+/**
+ * Instantiates a drawable XML file into its corresponding
+ * {@link android.graphics.drawable.Drawable} objects.
+ * <p>
+ * For performance reasons, inflation relies heavily on pre-processing of
+ * XML files that is done at build time. Therefore, it is not currently possible
+ * to use this inflater with an XmlPullParser over a plain XML file at runtime;
+ * it only works with an XmlPullParser returned from a compiled resource (R.
+ * <em>something</em> file.)
+ *
+ * @hide Pending API finalization.
+ */
+public final class DrawableInflater {
+    private static final HashMap<String, Constructor<? extends Drawable>> CONSTRUCTOR_MAP =
+            new HashMap<>();
+
+    private final Resources mRes;
+    private final ClassLoader mClassLoader;
+
+    /**
+     * Loads the drawable resource with the specified identifier.
+     *
+     * @param context the context in which the drawable should be loaded
+     * @param id the identifier of the drawable resource
+     * @return a drawable, or {@code null} if the drawable failed to load
+     */
+    @Nullable
+    public static Drawable loadDrawable(@NonNull Context context, @DrawableRes int id) {
+        return loadDrawable(context.getResources(), context.getTheme(), id);
+    }
+
+    /**
+     * Loads the drawable resource with the specified identifier.
+     *
+     * @param resources the resources from which the drawable should be loaded
+     * @param theme the theme against which the drawable should be inflated
+     * @param id the identifier of the drawable resource
+     * @return a drawable, or {@code null} if the drawable failed to load
+     */
+    @Nullable
+    public static Drawable loadDrawable(
+            @NonNull Resources resources, @Nullable Theme theme, @DrawableRes int id) {
+        return resources.getDrawable(id, theme);
+    }
+
+    /**
+     * Constructs a new drawable inflater using the specified resources and
+     * class loader.
+     *
+     * @param res the resources used to resolve resource identifiers
+     * @param classLoader the class loader used to load custom drawables
+     * @hide
+     */
+    public DrawableInflater(@NonNull Resources res, @NonNull ClassLoader classLoader) {
+        mRes = res;
+        mClassLoader = classLoader;
+    }
+
+    /**
+     * Inflates a drawable from inside an XML document using an optional
+     * {@link Theme}.
+     * <p>
+     * This method should be called on a parser positioned at a tag in an XML
+     * document defining a drawable resource. It will attempt to create a
+     * Drawable from the tag at the current position.
+     *
+     * @param name the name of the tag at the current position
+     * @param parser an XML parser positioned at the drawable tag
+     * @param attrs an attribute set that wraps the parser
+     * @param theme the theme against which the drawable should be inflated, or
+     *              {@code null} to not inflate against a theme
+     * @return a drawable
+     *
+     * @throws XmlPullParserException
+     * @throws IOException
+     */
+    @NonNull
+    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);
+        }
+        drawable.inflate(mRes, parser, attrs, theme);
+        return drawable;
+    }
+
+    @NonNull
+    @SuppressWarnings("deprecation")
+    private Drawable inflateFromTag(@NonNull String name) {
+        switch (name) {
+            case "selector":
+                return new StateListDrawable();
+            case "animated-selector":
+                return new AnimatedStateListDrawable();
+            case "level-list":
+                return new LevelListDrawable();
+            case "layer-list":
+                return new LayerDrawable();
+            case "transition":
+                return new TransitionDrawable();
+            case "ripple":
+                return new RippleDrawable();
+            case "color":
+                return new ColorDrawable();
+            case "shape":
+                return new GradientDrawable();
+            case "vector":
+                return new VectorDrawable();
+            case "animated-vector":
+                return new AnimatedVectorDrawable();
+            case "scale":
+                return new ScaleDrawable();
+            case "clip":
+                return new ClipDrawable();
+            case "rotate":
+                return new RotateDrawable();
+            case "animated-rotate":
+                return new AnimatedRotateDrawable();
+            case "animation-list":
+                return new AnimationDrawable();
+            case "inset":
+                return new InsetDrawable();
+            case "bitmap":
+                return new BitmapDrawable();
+            case "nine-patch":
+                return new NinePatchDrawable();
+            default:
+                return null;
+        }
+    }
+
+    @NonNull
+    private Drawable inflateFromClass(@NonNull String className) {
+        try {
+            Constructor<? extends Drawable> constructor;
+            synchronized (CONSTRUCTOR_MAP) {
+                constructor = CONSTRUCTOR_MAP.get(className);
+                if (constructor == null) {
+                    final Class<? extends Drawable> clazz =
+                            mClassLoader.loadClass(className).asSubclass(Drawable.class);
+                    constructor = clazz.getConstructor();
+                    CONSTRUCTOR_MAP.put(className, constructor);
+                }
+            }
+            return constructor.newInstance();
+        } catch (NoSuchMethodException e) {
+            final InflateException ie = new InflateException(
+                    "Error inflating class " + className);
+            ie.initCause(e);
+            throw ie;
+        } catch (ClassCastException e) {
+            // If loaded class is not a Drawable subclass.
+            final InflateException ie = new InflateException(
+                    "Class is not a Drawable " + className);
+            ie.initCause(e);
+            throw ie;
+        } catch (ClassNotFoundException e) {
+            // If loadClass fails, we should propagate the exception.
+            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);
+            ie.initCause(e);
+            throw ie;
+        }
+    }
+}
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index d9469d4..1a0ba6f 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();
     }
diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java
index 1c14e2f..f9474ef 100644
--- a/graphics/java/android/graphics/drawable/RippleBackground.java
+++ b/graphics/java/android/graphics/drawable/RippleBackground.java
@@ -48,8 +48,8 @@
     // Software rendering properties.
     private float mOpacity = 0;
 
-    public RippleBackground(RippleDrawable owner, Rect bounds) {
-        super(owner, bounds);
+    public RippleBackground(RippleDrawable owner, Rect bounds, boolean forceSoftware) {
+        super(owner, bounds, forceSoftware);
     }
 
     public boolean isVisible() {
@@ -131,15 +131,7 @@
         mPropX = CanvasProperty.createFloat(0);
         mPropY = CanvasProperty.createFloat(0);
 
-        // Linear "fast" enter based on current opacity.
         final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST);
-        if (fastEnterDuration > 0) {
-            final RenderNodeAnimator enter = new RenderNodeAnimator(
-                    mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
-            enter.setInterpolator(LINEAR_INTERPOLATOR);
-            enter.setDuration(fastEnterDuration);
-            set.add(enter);
-        }
 
         // Linear exit after enter is completed.
         final RenderNodeAnimator exit = new RenderNodeAnimator(
@@ -149,6 +141,15 @@
         exit.setStartDelay(fastEnterDuration);
         set.add(exit);
 
+        // Linear "fast" enter based on current opacity.
+        if (fastEnterDuration > 0) {
+            final RenderNodeAnimator enter = new RenderNodeAnimator(
+                    mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha);
+            enter.setInterpolator(LINEAR_INTERPOLATOR);
+            enter.setDuration(fastEnterDuration);
+            set.add(enter);
+        }
+
         return set;
     }
 
diff --git a/graphics/java/android/graphics/drawable/RippleComponent.java b/graphics/java/android/graphics/drawable/RippleComponent.java
index 23a3ee3..2d378c6 100644
--- a/graphics/java/android/graphics/drawable/RippleComponent.java
+++ b/graphics/java/android/graphics/drawable/RippleComponent.java
@@ -52,9 +52,16 @@
     /** Screen density used to adjust pixel-based constants. */
     protected float mDensity;
 
-    public RippleComponent(RippleDrawable owner, Rect bounds) {
+    /**
+     * If set, force all ripple animations to not run on RenderThread, even if it would be
+     * available.
+     */
+    private final boolean mForceSoftware;
+
+    public RippleComponent(RippleDrawable owner, Rect bounds, boolean forceSoftware) {
         mOwner = owner;
         mBounds = bounds;
+        mForceSoftware = forceSoftware;
     }
 
     public void onBoundsChange() {
@@ -143,7 +150,7 @@
      * @return {@code true} if something was drawn, {@code false} otherwise
      */
     public boolean draw(Canvas c, Paint p) {
-        final boolean hasDisplayListCanvas = c.isHardwareAccelerated()
+        final boolean hasDisplayListCanvas = !mForceSoftware && c.isHardwareAccelerated()
                 && c instanceof DisplayListCanvas;
         if (mHasDisplayListCanvas != hasDisplayListCanvas) {
             mHasDisplayListCanvas = hasDisplayListCanvas;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 32f6a89..2690223 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -166,6 +166,12 @@
     private boolean mOverrideBounds;
 
     /**
+     * If set, force all ripple animations to not run on RenderThread, even if it would be
+     * available.
+     */
+    private boolean mForceSoftware;
+
+    /**
      * Constructor used for drawable inflation.
      */
     RippleDrawable() {
@@ -546,7 +552,7 @@
      */
     private void tryBackgroundEnter(boolean focused) {
         if (mBackground == null) {
-            mBackground = new RippleBackground(this, mHotspotBounds);
+            mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware);
         }
 
         mBackground.setup(mState.mMaxRadius, mDensity);
@@ -584,7 +590,7 @@
             }
 
             final boolean isBounded = isBounded();
-            mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded);
+            mRipple = new RippleForeground(this, mHotspotBounds, x, y, isBounded, mForceSoftware);
         }
 
         mRipple.setup(mState.mMaxRadius, mDensity);
@@ -855,7 +861,8 @@
 
         // Position the shader to account for canvas translation.
         if (mMaskShader != null) {
-            mMaskMatrix.setTranslate(-x, -y);
+            final Rect bounds = getBounds();
+            mMaskMatrix.setTranslate(bounds.left - x, bounds.top - y);
             mMaskShader.setLocalMatrix(mMaskMatrix);
         }
 
@@ -948,6 +955,16 @@
         }
     }
 
+    /**
+     * Sets whether to disable RenderThread animations for this ripple.
+     *
+     * @param forceSoftware true if RenderThread animations should be disabled, false otherwise
+     * @hide
+     */
+    public void setForceSoftware(boolean forceSoftware) {
+        mForceSoftware = forceSoftware;
+    }
+
     @Override
     public ConstantState getConstantState() {
         return mState;
diff --git a/graphics/java/android/graphics/drawable/RippleForeground.java b/graphics/java/android/graphics/drawable/RippleForeground.java
index 4853b04..c660846 100644
--- a/graphics/java/android/graphics/drawable/RippleForeground.java
+++ b/graphics/java/android/graphics/drawable/RippleForeground.java
@@ -87,8 +87,8 @@
     private boolean mHasFinishedExit;
 
     public RippleForeground(RippleDrawable owner, Rect bounds, float startingX, float startingY,
-            boolean isBounded) {
-        super(owner, bounds);
+            boolean isBounded, boolean forceSoftware) {
+        super(owner, bounds, forceSoftware);
 
         mIsBounded = isBounded;
         mStartingX = startingX;
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index b3b3479..676ab1c 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,7 +162,6 @@
 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 += \
@@ -172,16 +180,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/Animator.cpp b/libs/hwui/Animator.cpp
index 512e0e2..5ca2a2f 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -36,8 +36,8 @@
         , mFinalValue(finalValue)
         , mDeltaValue(0)
         , mFromValue(0)
-        , mStagingPlayState(NOT_STARTED)
-        , mPlayState(NOT_STARTED)
+        , mStagingPlayState(PlayState::NotStarted)
+        , mPlayState(PlayState::NotStarted)
         , mHasStartValue(false)
         , mStartTime(0)
         , mDuration(300)
@@ -50,7 +50,7 @@
 
 void BaseRenderNodeAnimator::checkMutable() {
     // Should be impossible to hit as the Java-side also has guards for this
-    LOG_ALWAYS_FATAL_IF(mStagingPlayState != NOT_STARTED,
+    LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
             "Animator has already been started!");
 }
 
@@ -92,9 +92,9 @@
     if (mStagingPlayState > mPlayState) {
         mPlayState = mStagingPlayState;
         // Oh boy, we're starting! Man the battle stations!
-        if (mPlayState == RUNNING) {
+        if (mPlayState == PlayState::Running) {
             transitionToRunning(context);
-        } else if (mPlayState == FINISHED) {
+        } else if (mPlayState == PlayState::Finished) {
             callOnFinishedListener(context);
         }
     }
@@ -124,10 +124,10 @@
 }
 
 bool BaseRenderNodeAnimator::animate(AnimationContext& context) {
-    if (mPlayState < RUNNING) {
+    if (mPlayState < PlayState::Running) {
         return false;
     }
-    if (mPlayState == FINISHED) {
+    if (mPlayState == PlayState::Finished) {
         return true;
     }
 
@@ -141,18 +141,18 @@
     }
 
     float fraction = 1.0f;
-    if (mPlayState == RUNNING && mDuration > 0) {
+    if (mPlayState == PlayState::Running && mDuration > 0) {
         fraction = (float)(context.frameTimeMs() - mStartTime) / mDuration;
     }
     if (fraction >= 1.0f) {
         fraction = 1.0f;
-        mPlayState = FINISHED;
+        mPlayState = PlayState::Finished;
     }
 
     fraction = mInterpolator->interpolate(fraction);
     setValue(mTarget, mFromValue + (mDeltaValue * fraction));
 
-    if (mPlayState == FINISHED) {
+    if (mPlayState == PlayState::Finished) {
         callOnFinishedListener(context);
         return true;
     }
@@ -161,8 +161,8 @@
 }
 
 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
-    if (mPlayState < FINISHED) {
-        mPlayState = FINISHED;
+    if (mPlayState < PlayState::Finished) {
+        mPlayState = PlayState::Finished;
         callOnFinishedListener(context);
     }
 }
@@ -212,9 +212,9 @@
 }
 
 void RenderPropertyAnimator::onStagingPlayStateChanged() {
-    if (mStagingPlayState == RUNNING) {
+    if (mStagingPlayState == PlayState::Running) {
         (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
-    } else if (mStagingPlayState == FINISHED) {
+    } else if (mStagingPlayState == PlayState::Finished) {
         // We're being canceled, so make sure that whatever values the UI thread
         // is observing for us is pushed over
         mTarget->setPropertyFieldsDirty(dirtyMask());
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index 1b3d8e7..aea95bf 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -59,8 +59,8 @@
         mMayRunAsync = mayRunAsync;
     }
     bool mayRunAsync() { return mMayRunAsync; }
-    ANDROID_API void start() { mStagingPlayState = RUNNING; onStagingPlayStateChanged(); }
-    ANDROID_API void end() { mStagingPlayState = FINISHED; onStagingPlayStateChanged(); }
+    ANDROID_API void start() { mStagingPlayState = PlayState::Running; onStagingPlayStateChanged(); }
+    ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); }
 
     void attach(RenderNode* target);
     virtual void onAttached() {}
@@ -68,8 +68,8 @@
     void pushStaging(AnimationContext& context);
     bool animate(AnimationContext& context);
 
-    bool isRunning() { return mPlayState == RUNNING; }
-    bool isFinished() { return mPlayState == FINISHED; }
+    bool isRunning() { return mPlayState == PlayState::Running; }
+    bool isFinished() { return mPlayState == PlayState::Finished; }
     float finalValue() { return mFinalValue; }
 
     ANDROID_API virtual uint32_t dirtyMask() = 0;
@@ -77,6 +77,12 @@
     void forceEndNow(AnimationContext& context);
 
 protected:
+    enum class PlayState {
+        NotStarted,
+        Running,
+        Finished,
+    };
+
     BaseRenderNodeAnimator(float finalValue);
     virtual ~BaseRenderNodeAnimator();
 
@@ -88,12 +94,6 @@
 
     virtual void onStagingPlayStateChanged() {}
 
-    enum PlayState {
-        NOT_STARTED,
-        RUNNING,
-        FINISHED,
-    };
-
     RenderNode* mTarget;
 
     float mFinalValue;
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f663f07..ff71313 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -245,7 +245,7 @@
     FLUSH_LOGD("Flushing caches (mode %d)", mode);
 
     switch (mode) {
-        case kFlushMode_Full:
+        case FlushMode::Full:
             textureCache.clear();
             patchCache.clear();
             dropShadowCache.clear();
@@ -254,13 +254,13 @@
             fboCache.clear();
             dither.clear();
             // fall through
-        case kFlushMode_Moderate:
+        case FlushMode::Moderate:
             fontRenderer->flush();
             textureCache.flush();
             pathCache.clear();
             tessellationCache.clear();
             // fall through
-        case kFlushMode_Layers:
+        case FlushMode::Layers:
             layerCache.clear();
             renderBufferCache.clear();
             break;
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index a02e15d..929db17 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -83,10 +83,10 @@
     static Caches* sInstance;
 
 public:
-    enum FlushMode {
-        kFlushMode_Layers = 0,
-        kFlushMode_Moderate,
-        kFlushMode_Full
+    enum class FlushMode {
+        Layers = 0,
+        Moderate,
+        Full
     };
 
     /**
@@ -103,7 +103,7 @@
 
     /**
      * Destroys all resources associated with this cache. This should
-     * be called after a flush(kFlushMode_Full).
+     * be called after a flush(FlushMode::Full).
      */
     void terminate();
 
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 54fb5f2..e307ad9 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -155,17 +155,20 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool CanvasState::clipRect(float left, float top, float right, float bottom, SkRegion::Op op) {
-    mDirtyClip |= mSnapshot->clip(left, top, right, bottom, op);
+    mSnapshot->clip(left, top, right, bottom, op);
+    mDirtyClip = true;
     return !mSnapshot->clipIsEmpty();
 }
 
 bool CanvasState::clipPath(const SkPath* path, SkRegion::Op op) {
-    mDirtyClip |= mSnapshot->clipPath(*path, op);
+    mSnapshot->clipPath(*path, op);
+    mDirtyClip = true;
     return !mSnapshot->clipIsEmpty();
 }
 
 bool CanvasState::clipRegion(const SkRegion* region, SkRegion::Op op) {
-    mDirtyClip |= mSnapshot->clipRegionTransformed(*region, op);
+    mSnapshot->clipRegionTransformed(*region, op);
+    mDirtyClip = true;
     return !mSnapshot->clipIsEmpty();
 }
 
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index b1a6844..8e7efb4 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -32,9 +32,7 @@
 }
 
 static void handlePoint(Rect& transformedBounds, const Matrix4& transform, float x, float y) {
-    Vertex v;
-    v.x = x;
-    v.y = y;
+    Vertex v = {x, y};
     transform.mapPoint(v.x, v.y);
     transformedBounds.expandToCoverVertex(v.x, v.y);
 }
@@ -187,7 +185,7 @@
  */
 
 ClipArea::ClipArea()
-        : mMode(kModeRectangle) {
+        : mMode(Mode::Rectangle) {
 }
 
 /*
@@ -200,45 +198,46 @@
 }
 
 void ClipArea::setEmpty() {
-    mMode = kModeRectangle;
+    mMode = Mode::Rectangle;
     mClipRect.setEmpty();
     mClipRegion.setEmpty();
     mRectangleList.setEmpty();
 }
 
 void ClipArea::setClip(float left, float top, float right, float bottom) {
-    mMode = kModeRectangle;
+    mMode = Mode::Rectangle;
     mClipRect.set(left, top, right, bottom);
     mClipRegion.setEmpty();
 }
 
-bool ClipArea::clipRectWithTransform(float left, float top, float right,
+void ClipArea::clipRectWithTransform(float left, float top, float right,
         float bottom, const mat4* transform, SkRegion::Op op) {
     Rect r(left, top, right, bottom);
-    return clipRectWithTransform(r, transform, op);
+    clipRectWithTransform(r, transform, op);
 }
 
-bool ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
+void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
         SkRegion::Op op) {
     switch (mMode) {
-    case kModeRectangle:
-        return rectangleModeClipRectWithTransform(r, transform, op);
-    case kModeRectangleList:
-        return rectangleListModeClipRectWithTransform(r, transform, op);
-    case kModeRegion:
-        return regionModeClipRectWithTransform(r, transform, op);
+    case Mode::Rectangle:
+        rectangleModeClipRectWithTransform(r, transform, op);
+        break;
+    case Mode::RectangleList:
+        rectangleListModeClipRectWithTransform(r, transform, op);
+        break;
+    case Mode::Region:
+        regionModeClipRectWithTransform(r, transform, op);
+        break;
     }
-    return false;
 }
 
-bool ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
     enterRegionMode();
     mClipRegion.op(region, op);
     onClipRegionUpdated();
-    return true;
 }
 
-bool ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
+void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
         SkRegion::Op op) {
     SkMatrix skTransform;
     transform->copyTo(skTransform);
@@ -246,7 +245,7 @@
     path.transform(skTransform, &transformed);
     SkRegion region;
     regionFromPath(transformed, region);
-    return clipRegion(region, op);
+    clipRegion(region, op);
 }
 
 /*
@@ -257,19 +256,20 @@
     // Entering rectangle mode discards any
     // existing clipping information from the other modes.
     // The only way this occurs is by a clip setting operation.
-    mMode = kModeRectangle;
+    mMode = Mode::Rectangle;
 }
 
-bool ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
         const mat4* transform, SkRegion::Op op) {
 
     if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
         mClipRect = r;
         transform->mapRect(mClipRect);
-        return true;
+        return;
     } else if (op != SkRegion::kIntersect_Op) {
         enterRegionMode();
-        return regionModeClipRectWithTransform(r, transform, op);
+        regionModeClipRectWithTransform(r, transform, op);
+        return;
     }
 
     if (transform->rectToRect()) {
@@ -279,19 +279,18 @@
         if (!hasIntersection) {
             mClipRect.setEmpty();
         }
-        return true;
+        return;
     }
 
     enterRectangleListMode();
-    return rectangleListModeClipRectWithTransform(r, transform, op);
+    rectangleListModeClipRectWithTransform(r, transform, op);
 }
 
-bool ClipArea::rectangleModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleModeClipRectWithTransform(float left, float top,
         float right, float bottom, const mat4* transform, SkRegion::Op op) {
     Rect r(left, top, right, bottom);
-    bool result = rectangleModeClipRectWithTransform(r, transform, op);
+    rectangleModeClipRectWithTransform(r, transform, op);
     mClipRect = mRectangleList.calculateBounds();
-    return result;
 }
 
 /*
@@ -302,25 +301,24 @@
     // Is is only legal to enter rectangle list mode from
     // rectangle mode, since rectangle list mode cannot represent
     // all clip areas that can be represented by a region.
-    ALOG_ASSERT(mMode == kModeRectangle);
-    mMode = kModeRectangleList;
+    ALOG_ASSERT(mMode == Mode::Rectangle);
+    mMode = Mode::RectangleList;
     mRectangleList.set(mClipRect, Matrix4::identity());
 }
 
-bool ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
+void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
         const mat4* transform, SkRegion::Op op) {
     if (op != SkRegion::kIntersect_Op
             || !mRectangleList.intersectWith(r, *transform)) {
         enterRegionMode();
-        return regionModeClipRectWithTransform(r, transform, op);
+        regionModeClipRectWithTransform(r, transform, op);
     }
-    return true;
 }
 
-bool ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
+void ClipArea::rectangleListModeClipRectWithTransform(float left, float top,
         float right, float bottom, const mat4* transform, SkRegion::Op op) {
     Rect r(left, top, right, bottom);
-    return rectangleListModeClipRectWithTransform(r, transform, op);
+    rectangleListModeClipRectWithTransform(r, transform, op);
 }
 
 /*
@@ -329,9 +327,9 @@
 
 void ClipArea::enterRegionMode() {
     Mode oldMode = mMode;
-    mMode = kModeRegion;
-    if (oldMode != kModeRegion) {
-        if (oldMode == kModeRectangle) {
+    mMode = Mode::Region;
+    if (oldMode != Mode::Region) {
+        if (oldMode == Mode::Rectangle) {
             mClipRegion.setRect(mClipRect.left, mClipRect.top,
                     mClipRect.right, mClipRect.bottom);
         } else {
@@ -341,20 +339,18 @@
     }
 }
 
-bool ClipArea::regionModeClipRectWithTransform(const Rect& r,
+void ClipArea::regionModeClipRectWithTransform(const Rect& r,
         const mat4* transform, SkRegion::Op op) {
     SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
     SkRegion transformedRectRegion;
     regionFromPath(transformedRect, transformedRectRegion);
     mClipRegion.op(transformedRectRegion, op);
     onClipRegionUpdated();
-    return true;
 }
 
-bool ClipArea::regionModeClipRectWithTransform(float left, float top,
+void ClipArea::regionModeClipRectWithTransform(float left, float top,
         float right, float bottom, const mat4* transform, SkRegion::Op op) {
-    return regionModeClipRectWithTransform(Rect(left, top, right, bottom),
-            transform, op);
+    regionModeClipRectWithTransform(Rect(left, top, right, bottom), transform, op);
 }
 
 void ClipArea::onClipRegionUpdated() {
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 51ef27b..38fefe5 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -80,6 +80,13 @@
 };
 
 class ClipArea {
+private:
+    enum class Mode {
+        Rectangle,
+        Region,
+        RectangleList
+    };
+
 public:
     ClipArea();
 
@@ -91,12 +98,12 @@
 
     void setEmpty();
     void setClip(float left, float top, float right, float bottom);
-    bool clipRectWithTransform(float left, float top, float right, float bottom,
-            const mat4* transform, SkRegion::Op op = SkRegion::kIntersect_Op);
-    bool clipRectWithTransform(const Rect& r, const mat4* transform,
-            SkRegion::Op op = SkRegion::kIntersect_Op);
-    bool clipRegion(const SkRegion& region, SkRegion::Op op = SkRegion::kIntersect_Op);
-    bool clipPathWithTransform(const SkPath& path, const mat4* transform,
+    void clipRectWithTransform(float left, float top, float right, float bottom,
+            const mat4* transform, SkRegion::Op op);
+    void clipRectWithTransform(const Rect& r, const mat4* transform,
+            SkRegion::Op op);
+    void clipRegion(const SkRegion& region, SkRegion::Op op);
+    void clipPathWithTransform(const SkPath& path, const mat4* transform,
             SkRegion::Op op);
 
     const Rect& getClipRect() const {
@@ -112,41 +119,39 @@
     }
 
     bool isRegion() const {
-        return kModeRegion == mMode;
+        return Mode::Region == mMode;
     }
 
     bool isSimple() const {
-        return mMode == kModeRectangle;
+        return mMode == Mode::Rectangle;
     }
 
     bool isRectangleList() const {
-        return mMode == kModeRectangleList;
+        return mMode == Mode::RectangleList;
     }
 
 private:
     void enterRectangleMode();
-    bool rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
-    bool rectangleModeClipRectWithTransform(float left, float top, float right,
+    void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+    void rectangleModeClipRectWithTransform(float left, float top, float right,
             float bottom, const mat4* transform, SkRegion::Op op);
 
     void enterRectangleListMode();
-    bool rectangleListModeClipRectWithTransform(float left, float top,
+    void rectangleListModeClipRectWithTransform(float left, float top,
             float right, float bottom, const mat4* transform, SkRegion::Op op);
-    bool rectangleListModeClipRectWithTransform(const Rect& r,
+    void rectangleListModeClipRectWithTransform(const Rect& r,
             const mat4* transform, SkRegion::Op op);
 
     void enterRegionModeFromRectangleMode();
     void enterRegionModeFromRectangleListMode();
     void enterRegionMode();
-    bool regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+    void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
             SkRegion::Op op);
-    bool regionModeClipRectWithTransform(float left, float top, float right,
+    void regionModeClipRectWithTransform(float left, float top, float right,
             float bottom, const mat4* transform, SkRegion::Op op);
 
     void ensureClipRegion();
     void onClipRegionUpdated();
-    bool clipRegionOp(float left, float top, float right, float bottom,
-            SkRegion::Op op);
 
     SkRegion createViewportRegion() {
         return SkRegion(mViewportBounds.toSkIRect());
@@ -158,12 +163,6 @@
         pathAsRegion.setPath(path, createViewportRegion());
     }
 
-    enum Mode {
-        kModeRectangle,
-        kModeRegion,
-        kModeRectangleList
-    };
-
     Mode mMode;
     Rect mViewportBounds;
     Rect mClipRect;
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index bb149fe..506bfad 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -216,11 +216,11 @@
     addRenderNodeOp(op);
 }
 
-void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle, float x, float y) {
+void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
     // We ref the DeferredLayerUpdater due to its thread-safe ref-counting
     // semantics.
     mDisplayListData->ref(layerHandle);
-    addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer(), x, y));
+    addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer()));
 }
 
 void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
diff --git a/libs/hwui/DisplayListCanvas.h b/libs/hwui/DisplayListCanvas.h
index f29e835..392bb3e 100644
--- a/libs/hwui/DisplayListCanvas.h
+++ b/libs/hwui/DisplayListCanvas.h
@@ -91,7 +91,7 @@
 // ----------------------------------------------------------------------------
 // HWUI Canvas draw operations - special
 // ----------------------------------------------------------------------------
-    void drawLayer(DeferredLayerUpdater* layerHandle, float x, float y);
+    void drawLayer(DeferredLayerUpdater* layerHandle);
     void drawRenderNode(RenderNode* renderNode);
 
     // TODO: rename for consistency
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 8bb892f..14126a9 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -1524,23 +1524,21 @@
 
 class DrawLayerOp : public DrawOp {
 public:
-    DrawLayerOp(Layer* layer, float x, float y)
-            : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {}
+    DrawLayerOp(Layer* layer)
+            : DrawOp(nullptr), mLayer(layer) {}
 
     virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override {
-        renderer.drawLayer(mLayer, mX, mY);
+        renderer.drawLayer(mLayer);
     }
 
     virtual void output(int level, uint32_t logFlags) const override {
-        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
+        OP_LOG("Draw Layer %p", mLayer);
     }
 
     virtual const char* name() override { return "DrawLayer"; }
 
 private:
     Layer* mLayer;
-    float mX;
-    float mY;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index c9e3880..e27b26b 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -274,7 +274,7 @@
         SkXfermode::Mode mode;
         SkScalar srcColorMatrix[20];
         if (colorFilter->asColorMode(&color, &mode)) {
-            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorBlend;
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
             mDescription.colorMode = mode;
 
             const float alpha = SkColorGetA(color) / 255.0f;
@@ -286,7 +286,7 @@
                     alpha,
             };
         } else if (colorFilter->asColorMatrix(srcColorMatrix)) {
-            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::kColorMatrix;
+            mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
 
             float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
             memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
@@ -305,7 +305,7 @@
             LOG_ALWAYS_FATAL("unsupported ColorFilter");
         }
     } else {
-        mOutGlop->fill.filterMode = ProgramDescription::kColorNone;
+        mOutGlop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
     }
 }
 
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 928f91b..e748221 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -36,7 +36,7 @@
 namespace uirenderer {
 
 Layer::Layer(Type layerType, RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight)
-        : state(kState_Uncached)
+        : state(State::Uncached)
         , caches(Caches::getInstance())
         , renderState(renderState)
         , texture(caches)
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index b670870..e90f055 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -56,19 +56,19 @@
  */
 class Layer : public VirtualLightRefBase {
 public:
-    enum Type {
-        kType_Texture,
-        kType_DisplayList,
+    enum class Type {
+        Texture,
+        DisplayList,
     };
 
     // layer lifecycle, controlled from outside
-    enum State {
-        kState_Uncached = 0,
-        kState_InCache = 1,
-        kState_FailedToCache = 2,
-        kState_RemovedFromCache = 3,
-        kState_DeletedFromCache = 4,
-        kState_InGarbageList = 5,
+    enum class State {
+        Uncached = 0,
+        InCache = 1,
+        FailedToCache = 2,
+        RemovedFromCache = 3,
+        DeletedFromCache = 4,
+        InGarbageList = 5,
     };
     State state; // public for logging/debugging purposes
 
@@ -241,7 +241,7 @@
     }
 
     inline bool isTextureLayer() const {
-        return type == kType_Texture;
+        return type == Type::Texture;
     }
 
     inline SkColorFilter* getColorFilter() const {
diff --git a/libs/hwui/LayerCache.cpp b/libs/hwui/LayerCache.cpp
index 33f40b0..39cadd1 100644
--- a/libs/hwui/LayerCache.cpp
+++ b/libs/hwui/LayerCache.cpp
@@ -81,7 +81,7 @@
         LAYER_LOGD("Destroying layer %dx%d, fbo %d", layer->getWidth(), layer->getHeight(),
                 layer->getFbo());
         mSize -= layer->getWidth() * layer->getHeight() * 4;
-        layer->state = Layer::kState_DeletedFromCache;
+        layer->state = Layer::State::DeletedFromCache;
         layer->decStrong(nullptr);
     }
 }
@@ -104,14 +104,14 @@
         mCache.erase(iter);
 
         layer = entry.mLayer;
-        layer->state = Layer::kState_RemovedFromCache;
+        layer->state = Layer::State::RemovedFromCache;
         mSize -= layer->getWidth() * layer->getHeight() * 4;
 
         LAYER_LOGD("Reusing layer %dx%d", layer->getWidth(), layer->getHeight());
     } else {
         LAYER_LOGD("Creating new layer %dx%d", entry.mWidth, entry.mHeight);
 
-        layer = new Layer(Layer::kType_DisplayList, renderState, entry.mWidth, entry.mHeight);
+        layer = new Layer(Layer::Type::DisplayList, renderState, entry.mWidth, entry.mHeight);
         layer->setBlend(true);
         layer->generateTexture();
         layer->bindTexture();
@@ -156,11 +156,11 @@
         mCache.insert(entry);
         mSize += size;
 
-        layer->state = Layer::kState_InCache;
+        layer->state = Layer::State::InCache;
         return true;
     }
 
-    layer->state = Layer::kState_FailedToCache;
+    layer->state = Layer::State::FailedToCache;
     return false;
 }
 
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 00add29..d8e6392 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -272,7 +272,7 @@
 Layer* LayerRenderer::createTextureLayer(RenderState& renderState) {
     LAYER_RENDERER_LOGD("Creating new texture layer");
 
-    Layer* layer = new Layer(Layer::kType_Texture, renderState, 0, 0);
+    Layer* layer = new Layer(Layer::Type::Texture, renderState, 0, 0);
     layer->setCacheable(false);
     layer->layer.set(0.0f, 0.0f, 0.0f, 0.0f);
     layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index b35c017..5692d7e 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2268,7 +2268,7 @@
     mDirty = true;
 }
 
-void OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
+void OpenGLRenderer::drawLayer(Layer* layer) {
     if (!layer) {
         return;
     }
@@ -2284,7 +2284,7 @@
 
     bool clipRequired = false;
     const bool rejected = mState.calculateQuickRejectForScissor(
-            x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(),
+            0, 0, layer->layer.getWidth(), layer->layer.getHeight(),
             &clipRequired, nullptr, false);
 
     if (rejected) {
@@ -2313,7 +2313,7 @@
                     .setMeshTexturedIndexedQuads(layer->mesh, layer->meshElementCount)
                     .setFillLayer(layer->getTexture(), layer->getColorFilter(), getLayerAlpha(layer), layer->getMode(), Blend::ModeOrderSwap::NoSwap)
                     .setTransform(*currentSnapshot(),  TransformFlags::None)
-                    .setModelViewOffsetRectSnap(x, y, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
+                    .setModelViewOffsetRectSnap(0, 0, Rect(0, 0, layer->layer.getWidth(), layer->layer.getHeight()))
                     .build();
             DRAW_DOUBLE_STENCIL_IF(!layer->hasDrawnSinceUpdate, renderGlop(glop));
 #if DEBUG_LAYERS_AS_REGIONS
@@ -2326,7 +2326,7 @@
 
             SkPaint paint;
             paint.setColor(0x7f00ff00);
-            drawColorRect(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight(), &paint);
+            drawColorRect(0, 0, layer->layer.getWidth(), layer->layer.getHeight(), &paint);
         }
     }
     layer->hasDrawnSinceUpdate = true;
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 45662a7..af85e8c 100755
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -35,6 +35,7 @@
 #include <SkBitmap.h>
 #include <SkCanvas.h>
 #include <SkColorFilter.h>
+#include <SkDrawLooper.h>
 #include <SkMatrix.h>
 #include <SkPaint.h>
 #include <SkRegion.h>
@@ -187,7 +188,7 @@
             const SkPaint* paint, int flags);
 
     void drawRenderNode(RenderNode* displayList, Rect& dirty, int32_t replayFlags = 1);
-    void drawLayer(Layer* layer, float x, float y);
+    void drawLayer(Layer* layer);
     void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     void drawBitmaps(const SkBitmap* bitmap, AssetAtlas::Entry* entry, int bitmapCount,
             TextureVertex* vertices, bool pureTranslate, const Rect& bounds, const SkPaint* paint);
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 8d4d4f0..922ff7c 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,15 +26,22 @@
 
 class Outline {
 public:
+    enum class Type {
+        None = 0,
+        Empty = 1,
+        ConvexPath = 2,
+        RoundRect = 3
+    };
+
     Outline()
             : mShouldClip(false)
-            , mType(kOutlineType_None)
+            , mType(Type::None)
             , mRadius(0)
             , mAlpha(0.0f) {}
 
     void setRoundRect(int left, int top, int right, int bottom, float radius, float alpha) {
         mAlpha = alpha;
-        if (mType == kOutlineType_RoundRect
+        if (mType == Type::RoundRect
                 && left == mBounds.left
                 && right == mBounds.right
                 && top == mBounds.top
@@ -44,7 +51,7 @@
             return;
         }
 
-        mType = kOutlineType_RoundRect;
+        mType = Type::RoundRect;
         mBounds.set(left, top, right, bottom);
         mRadius = radius;
 
@@ -63,26 +70,26 @@
             setEmpty();
             return;
         }
-        mType = kOutlineType_ConvexPath;
+        mType = Type::ConvexPath;
         mPath = *outline;
         mBounds.set(outline->getBounds());
         mAlpha = alpha;
     }
 
     void setEmpty() {
-        mType = kOutlineType_Empty;
+        mType = Type::Empty;
         mPath.reset();
         mAlpha = 0.0f;
     }
 
     void setNone() {
-        mType = kOutlineType_None;
+        mType = Type::None;
         mPath.reset();
         mAlpha = 0.0f;
     }
 
     bool isEmpty() const {
-        return mType == kOutlineType_Empty;
+        return mType == Type::Empty;
     }
 
     float getAlpha() const {
@@ -99,7 +106,7 @@
 
     bool willClip() const {
         // only round rect outlines can be used for clipping
-        return mShouldClip && (mType == kOutlineType_RoundRect);
+        return mShouldClip && (mType == Type::RoundRect);
     }
 
     bool willRoundRectClip() const {
@@ -108,7 +115,7 @@
     }
 
     bool getAsRoundRect(Rect* outRect, float* outRadius) const {
-        if (mType == kOutlineType_RoundRect) {
+        if (mType == Type::RoundRect) {
             outRect->set(mBounds);
             *outRadius = mRadius;
             return true;
@@ -117,21 +124,26 @@
     }
 
     const SkPath* getPath() const {
-        if (mType == kOutlineType_None || mType == kOutlineType_Empty) return nullptr;
+        if (mType == Type::None || mType == Type::Empty) return nullptr;
 
         return &mPath;
     }
 
-private:
-    enum OutlineType {
-        kOutlineType_None = 0,
-        kOutlineType_Empty = 1,
-        kOutlineType_ConvexPath = 2,
-        kOutlineType_RoundRect = 3
-    };
+    Type getType() const {
+        return mType;
+    }
 
+    const Rect& getBounds() const {
+        return mBounds;
+    }
+
+    float getRadius() const {
+        return mRadius;
+    }
+
+private:
     bool mShouldClip;
-    OutlineType mType;
+    Type mType;
     Rect mBounds;
     float mRadius;
     float mAlpha;
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index af1e4a7..b09c207 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -103,10 +103,10 @@
  * A ProgramDescription must be used in conjunction with a ProgramCache.
  */
 struct ProgramDescription {
-    enum ColorFilterMode {
-        kColorNone = 0,
-        kColorMatrix,
-        kColorBlend
+    enum class ColorFilterMode {
+        None = 0,
+        Matrix,
+        Blend
     };
 
     enum Gradient {
@@ -193,7 +193,7 @@
         bitmapWrapS = GL_CLAMP_TO_EDGE;
         bitmapWrapT = GL_CLAMP_TO_EDGE;
 
-        colorOp = kColorNone;
+        colorOp = ColorFilterMode::None;
         colorMode = SkXfermode::kClear_Mode;
 
         framebufferMode = SkXfermode::kClear_Mode;
@@ -249,14 +249,14 @@
             key |= (shadersMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_SHADER_SHIFT;
         }
         switch (colorOp) {
-            case kColorMatrix:
+            case ColorFilterMode::Matrix:
                 key |= PROGRAM_KEY_COLOR_MATRIX;
                 break;
-            case kColorBlend:
+            case ColorFilterMode::Blend:
                 key |= PROGRAM_KEY_COLOR_BLEND;
                 key |= (colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
                 break;
-            case kColorNone:
+            case ColorFilterMode::None:
                 break;
         }
         key |= (framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index 7f16deb..b25a4ac 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -38,7 +38,8 @@
 // Vertex shaders snippets
 ///////////////////////////////////////////////////////////////////////////////
 
-const char* gVS_Header_Attributes =
+const char* gVS_Header_Start =
+        "#version 100\n"
         "attribute vec4 position;\n";
 const char* gVS_Header_Attributes_TexCoords =
         "attribute vec2 texCoords;\n";
@@ -132,6 +133,8 @@
 // Fragment shaders snippets
 ///////////////////////////////////////////////////////////////////////////////
 
+const char* gFS_Header_Start =
+        "#version 100\n";
 const char* gFS_Header_Extension_FramebufferFetch =
         "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
 const char* gFS_Header_Extension_ExternalTexture =
@@ -457,7 +460,7 @@
 
 String8 ProgramCache::generateVertexShader(const ProgramDescription& description) {
     // Add attributes
-    String8 shader(gVS_Header_Attributes);
+    String8 shader(gVS_Header_Start);
     if (description.hasTexture || description.hasExternalTexture) {
         shader.append(gVS_Header_Attributes_TexCoords);
     }
@@ -543,7 +546,7 @@
 }
 
 String8 ProgramCache::generateFragmentShader(const ProgramDescription& description) {
-    String8 shader;
+    String8 shader(gFS_Header_Start);
 
     const bool blendFramebuffer = description.framebufferMode >= SkXfermode::kPlus_Mode;
     if (blendFramebuffer) {
@@ -604,7 +607,7 @@
     if (!description.hasVertexAlpha
             && !blendFramebuffer
             && !description.hasColors
-            && description.colorOp == ProgramDescription::kColorNone
+            && description.colorOp == ProgramDescription::ColorFilterMode::None
             && !description.hasDebugHighlight
             && !description.hasRoundRectClip) {
         bool fast = false;
@@ -668,13 +671,13 @@
     if (description.hasBitmap) {
         shader.append(gFS_Uniforms_BitmapSampler);
     }
-    shader.append(gFS_Uniforms_ColorOp[description.colorOp]);
+    shader.append(gFS_Uniforms_ColorOp[static_cast<int>(description.colorOp)]);
 
     // Generate required functions
     if (description.hasGradient && description.hasBitmap) {
         generateBlend(shader, "blendShaders", description.shadersMode);
     }
-    if (description.colorOp == ProgramDescription::kColorBlend) {
+    if (description.colorOp == ProgramDescription::ColorFilterMode::Blend) {
         generateBlend(shader, "blendColors", description.colorMode);
     }
     if (blendFramebuffer) {
@@ -737,7 +740,7 @@
         }
 
         // Apply the color op if needed
-        shader.append(gFS_Main_ApplyColorOp[description.colorOp]);
+        shader.append(gFS_Main_ApplyColorOp[static_cast<int>(description.colorOp)]);
 
         if (description.hasVertexAlpha) {
             if (description.useShadowAlphaInterp) {
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 73c0107..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) {
@@ -710,8 +785,8 @@
         OpenGLRenderer& renderer, T& handler) {
     const int size = zTranslatedNodes.size();
     if (size == 0
-            || (mode == kNegativeZChildren && zTranslatedNodes[0].key > 0.0f)
-            || (mode == kPositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
+            || (mode == ChildrenSelectMode::NegativeZChildren && zTranslatedNodes[0].key > 0.0f)
+            || (mode == ChildrenSelectMode::PositiveZChildren && zTranslatedNodes[size - 1].key < 0.0f)) {
         // no 3d children to draw
         return;
     }
@@ -730,7 +805,7 @@
      */
     const size_t nonNegativeIndex = findNonNegativeIndex(zTranslatedNodes);
     size_t drawIndex, shadowIndex, endIndex;
-    if (mode == kNegativeZChildren) {
+    if (mode == ChildrenSelectMode::NegativeZChildren) {
         drawIndex = 0;
         endIndex = nonNegativeIndex;
         shadowIndex = endIndex; // draw no shadows
@@ -875,7 +950,7 @@
         renderer.setBaseTransform(initialTransform);
 
         if (drawLayer) {
-            handler(new (alloc) DrawLayerOp(mLayer, 0, 0),
+            handler(new (alloc) DrawLayerOp(mLayer),
                     renderer.getSaveCount() - 1, properties().getClipToBounds());
         } else {
             const int saveCountOffset = renderer.getSaveCount() - 1;
@@ -886,7 +961,7 @@
                 std::vector<ZDrawRenderNodeOpPair> zTranslatedNodes;
                 buildZSortedChildList(chunk, zTranslatedNodes);
 
-                issueOperationsOf3dChildren(kNegativeZChildren,
+                issueOperationsOf3dChildren(ChildrenSelectMode::NegativeZChildren,
                         initialTransform, zTranslatedNodes, renderer, handler);
 
 
@@ -903,7 +978,7 @@
                     }
                 }
 
-                issueOperationsOf3dChildren(kPositiveZChildren,
+                issueOperationsOf3dChildren(ChildrenSelectMode::PositiveZChildren,
                         initialTransform, zTranslatedNodes, renderer, handler);
             }
         }
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 6d1a2b7..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();
@@ -184,9 +188,9 @@
         return nodes.size();
     }
 
-    enum ChildrenSelectMode {
-        kNegativeZChildren,
-        kPositiveZChildren
+    enum class ChildrenSelectMode {
+        NegativeZChildren,
+        PositiveZChildren
     };
 
     void computeOrderingImpl(DrawRenderNodeOp* opState,
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/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 1f95946..6c105cf 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -32,12 +32,19 @@
 // Support
 ///////////////////////////////////////////////////////////////////////////////
 
-static const GLenum gTileModes[] = {
+static constexpr GLenum gTileModes[] = {
         GL_CLAMP_TO_EDGE,   // == SkShader::kClamp_TileMode
         GL_REPEAT,          // == SkShader::kRepeat_Mode
         GL_MIRRORED_REPEAT  // == SkShader::kMirror_TileMode
 };
 
+static_assert(gTileModes[SkShader::kClamp_TileMode] == GL_CLAMP_TO_EDGE,
+        "SkShader TileModes have changed");
+static_assert(gTileModes[SkShader::kRepeat_TileMode] == GL_REPEAT,
+        "SkShader TileModes have changed");
+static_assert(gTileModes[SkShader::kMirror_TileMode] == GL_MIRRORED_REPEAT,
+        "SkShader TileModes have changed");
+
 /**
  * This function does not work for n == 0.
  */
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index ca19a42..4d60b8d 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -83,24 +83,24 @@
 // Clipping
 ///////////////////////////////////////////////////////////////////////////////
 
-bool Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
+void Snapshot::clipRegionTransformed(const SkRegion& region, SkRegion::Op op) {
     flags |= Snapshot::kFlagClipSet;
-    return mClipArea->clipRegion(region, op);
+    mClipArea->clipRegion(region, op);
 }
 
-bool Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
+void Snapshot::clip(float left, float top, float right, float bottom, SkRegion::Op op) {
     flags |= Snapshot::kFlagClipSet;
-    return mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
+    mClipArea->clipRectWithTransform(left, top, right, bottom, transform, op);
 }
 
-bool Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
+void Snapshot::clipPath(const SkPath& path, SkRegion::Op op) {
     flags |= Snapshot::kFlagClipSet;
-    return mClipArea->clipPathWithTransform(path, transform, op);
+    mClipArea->clipPathWithTransform(path, transform, op);
 }
 
 void Snapshot::setClip(float left, float top, float right, float bottom) {
-    mClipArea->setClip(left, top, right, bottom);
     flags |= Snapshot::kFlagClipSet;
+    mClipArea->setClip(left, top, right, bottom);
 }
 
 bool Snapshot::hasPerspectiveTransform() const {
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index af6ad72..cf8f11c 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -124,26 +124,25 @@
      * the specified operation. The specified rectangle is transformed
      * by this snapshot's trasnformation.
      */
-    bool clip(float left, float top, float right, float bottom,
-            SkRegion::Op op = SkRegion::kIntersect_Op);
+    void clip(float left, float top, float right, float bottom, SkRegion::Op op);
 
     /**
      * Modifies the current clip with the new clip rectangle and
      * the specified operation. The specified rectangle is considered
      * already transformed.
      */
-    bool clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
+    void clipTransformed(const Rect& r, SkRegion::Op op = SkRegion::kIntersect_Op);
 
     /**
      * Modifies the current clip with the specified region and operation.
      * The specified region is considered already transformed.
      */
-    bool clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
+    void clipRegionTransformed(const SkRegion& region, SkRegion::Op op);
 
     /**
      * Modifies the current clip with the specified path and operation.
      */
-    bool clipPath(const SkPath& path, SkRegion::Op op);
+    void clipPath(const SkPath& path, SkRegion::Op op);
 
     /**
      * Sets the current clip.
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/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index 29927ed..b21e15e 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -30,6 +30,26 @@
     GLenum dst;
 };
 
+// assumptions made by lookup tables in either this file or ProgramCache
+static_assert(0 == SkXfermode::kClear_Mode, "SkXfermode enums have changed");
+static_assert(1 == SkXfermode::kSrc_Mode, "SkXfermode enums have changed");
+static_assert(2 == SkXfermode::kDst_Mode, "SkXfermode enums have changed");
+static_assert(3 == SkXfermode::kSrcOver_Mode, "SkXfermode enums have changed");
+static_assert(4 == SkXfermode::kDstOver_Mode, "SkXfermode enums have changed");
+static_assert(5 == SkXfermode::kSrcIn_Mode, "SkXfermode enums have changed");
+static_assert(6 == SkXfermode::kDstIn_Mode, "SkXfermode enums have changed");
+static_assert(7 == SkXfermode::kSrcOut_Mode, "SkXfermode enums have changed");
+static_assert(8 == SkXfermode::kDstOut_Mode, "SkXfermode enums have changed");
+static_assert(9 == SkXfermode::kSrcATop_Mode, "SkXfermode enums have changed");
+static_assert(10 == SkXfermode::kDstATop_Mode, "SkXfermode enums have changed");
+static_assert(11 == SkXfermode::kXor_Mode, "SkXfermode enums have changed");
+static_assert(12 == SkXfermode::kPlus_Mode, "SkXfermode enums have changed");
+static_assert(13 == SkXfermode::kModulate_Mode, "SkXfermode enums have changed");
+static_assert(14 == SkXfermode::kScreen_Mode, "SkXfermode enums have changed");
+static_assert(15 == SkXfermode::kOverlay_Mode, "SkXfermode enums have changed");
+static_assert(16 == SkXfermode::kDarken_Mode, "SkXfermode enums have changed");
+static_assert(17 == SkXfermode::kLighten_Mode, "SkXfermode enums have changed");
+
 // In this array, the index of each Blender equals the value of the first
 // entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
 const Blender kBlends[] = {
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index b5ed9e6..c5126de 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -229,11 +229,11 @@
             glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
 
     // Color filter uniforms
-    if (fill.filterMode == ProgramDescription::kColorBlend) {
+    if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
         const FloatColor& color = fill.filter.color;
         glUniform4f(mCaches->program().getUniform("colorBlend"),
                 color.r, color.g, color.b, color.a);
-    } else if (fill.filterMode == ProgramDescription::kColorMatrix) {
+    } else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
         glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
                 fill.filter.matrix.matrix);
         glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index 319cfe4..d25ad51 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -34,10 +34,6 @@
 #define STENCIL_MASK_VALUE 0x1
 #endif
 
-Stencil::Stencil()
-        : mState(kDisabled) {
-}
-
 uint8_t Stencil::getStencilSize() {
     return STENCIL_BUFFER_SIZE;
 }
@@ -64,14 +60,14 @@
     glClearStencil(0);
     glClear(GL_STENCIL_BUFFER_BIT);
 
-    if (mState == kTest) {
+    if (mState == StencilState::Test) {
         // reset to test state, with immutable stencil
         glStencilMask(0);
     }
 }
 
 void Stencil::enableTest(int incrementThreshold) {
-    if (mState != kTest) {
+    if (mState != StencilState::Test) {
         enable();
         if (incrementThreshold > 0) {
             glStencilFunc(GL_EQUAL, incrementThreshold, 0xff);
@@ -82,12 +78,12 @@
         glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
         glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
         glStencilMask(0);
-        mState = kTest;
+        mState = StencilState::Test;
     }
 }
 
 void Stencil::enableWrite(int incrementThreshold) {
-    if (mState != kWrite) {
+    if (mState != StencilState::Write) {
         enable();
         if (incrementThreshold > 0) {
             glStencilFunc(GL_ALWAYS, 1, 0xff);
@@ -100,7 +96,7 @@
         }
         glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
         glStencilMask(0xff);
-        mState = kWrite;
+        mState = StencilState::Write;
     }
 }
 
@@ -109,7 +105,7 @@
     glStencilFunc(greater ? GL_LESS : GL_EQUAL, value, 0xffffffff);
     // We only want to test, let's keep everything
     glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-    mState = kTest;
+    mState = StencilState::Test;
     glStencilMask(0);
 }
 
@@ -119,20 +115,20 @@
     // The test always passes so the first two values are meaningless
     glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
     glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
-    mState = kWrite;
+    mState = StencilState::Write;
     glStencilMask(0xff);
 }
 
 void Stencil::enable() {
-    if (mState == kDisabled) {
+    if (mState == StencilState::Disabled) {
         glEnable(GL_STENCIL_TEST);
     }
 }
 
 void Stencil::disable() {
-    if (mState != kDisabled) {
+    if (mState != StencilState::Disabled) {
         glDisable(GL_STENCIL_TEST);
-        mState = kDisabled;
+        mState = StencilState::Disabled;
     }
 }
 
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
index 3261823..5f7d405 100644
--- a/libs/hwui/renderstate/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -30,8 +30,6 @@
 
 class ANDROID_API Stencil {
 public:
-    Stencil();
-
     /**
      * Returns the desired size for the stencil buffer. If the returned value
      * is 0, then no stencil buffer is required.
@@ -81,32 +79,31 @@
      * Indicates whether either test or write is enabled.
      */
     bool isEnabled() {
-        return mState != kDisabled;
+        return mState != StencilState::Disabled;
     }
 
     /**
      * Indicates whether testing only is enabled.
      */
     bool isTestEnabled() {
-        return mState == kTest;
+        return mState == StencilState::Test;
     }
 
     bool isWriteEnabled() {
-        return mState == kWrite;
+        return mState == StencilState::Write;
     }
 
     void dump();
 
 private:
-    void enable();
-
-    enum StencilState {
-        kDisabled,
-        kTest,
-        kWrite
+    enum class StencilState {
+        Disabled,
+        Test,
+        Write
     };
 
-    StencilState mState;
+    void enable();
+    StencilState mState = StencilState::Disabled;
 
 }; // class Stencil
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 67c42f3..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
@@ -421,7 +428,7 @@
         // Make sure to release all the textures we were owning as there won't
         // be another draw
         caches.textureCache.resetMarkInUse(this);
-        caches.flush(Caches::kFlushMode_Layers);
+        caches.flush(Caches::FlushMode::Layers);
     }
 }
 
@@ -431,10 +438,10 @@
 
     ATRACE_CALL();
     if (level >= TRIM_MEMORY_COMPLETE) {
-        Caches::getInstance().flush(Caches::kFlushMode_Full);
+        Caches::getInstance().flush(Caches::FlushMode::Full);
         thread.eglManager().destroy();
     } else if (level >= TRIM_MEMORY_UI_HIDDEN) {
-        Caches::getInstance().flush(Caches::kFlushMode_Moderate);
+        Caches::getInstance().flush(Caches::FlushMode::Moderate);
     }
 }
 
@@ -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/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
index f4943d5..bc2dae1 100644
--- a/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
+++ b/location/lib/java/com/android/location/provider/ActivityRecognitionProvider.java
@@ -42,6 +42,8 @@
     public static final String ACTIVITY_STILL = "android.activity_recognition.still";
     public static final String ACTIVITY_TILTING = "android.activity_recognition.tilting";
 
+    // NOTE: when adding an additional EVENT_TYPE_, EVENT_TYPE_COUNT needs to be updated in
+    // android.hardware.location.ActivityRecognitionHardware
     public static final int EVENT_TYPE_FLUSH_COMPLETE = 0;
     public static final int EVENT_TYPE_ENTER = 1;
     public static final int EVENT_TYPE_EXIT = 2;
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 0f1be6b..e92f294 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -671,15 +671,15 @@
             case USAGE_VOICE_COMMUNICATION:
                 return new String("USAGE_VOICE_COMMUNICATION");
             case USAGE_VOICE_COMMUNICATION_SIGNALLING:
-                return new String("USAGE_VOICE_COMMUNICATION");
+                return new String("USAGE_VOICE_COMMUNICATION_SIGNALLING");
             case USAGE_ALARM:
                 return new String("USAGE_ALARM");
             case USAGE_NOTIFICATION:
                 return new String("USAGE_NOTIFICATION");
             case USAGE_NOTIFICATION_RINGTONE:
-                return new String("USAGE_NOTIFICATION");
+                return new String("USAGE_NOTIFICATION_RINGTONE");
             case USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
-                return new String("USAGE_NOTIFICATION");
+                return new String("USAGE_NOTIFICATION_COMMUNICATION_REQUEST");
             case USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
                 return new String("USAGE_NOTIFICATION_COMMUNICATION_INSTANT");
             case USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index e99a37a..c59d1c7 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -279,6 +279,7 @@
     public static final int PERMISSION_DENIED  = -4;
     public static final int NO_INIT            = -5;
     public static final int DEAD_OBJECT        = -6;
+    public static final int WOULD_BLOCK        = -7;
 
     /*
      * AudioPolicyService methods
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 8880dad..bb4f7d9 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -158,6 +158,18 @@
      * Denotes a failure due to the improper use of a method.
      */
     public  static final int ERROR_INVALID_OPERATION               = AudioSystem.INVALID_OPERATION;
+    /**
+     * An error code indicating that the object reporting it is no longer valid and needs to
+     * be recreated.
+     * @hide
+     */
+    public  static final int ERROR_DEAD_OBJECT                     = AudioSystem.DEAD_OBJECT;
+    /**
+     * {@link #getTimestampWithStatus(AudioTimestamp)} is called in STOPPED or FLUSHED state,
+     * or immediately after start/ACTIVE.
+     * @hide
+     */
+    public  static final int ERROR_WOULD_BLOCK                     = AudioSystem.WOULD_BLOCK;
 
     // Error codes:
     // to keep in sync with frameworks/base/core/jni/android_media_AudioTrack.cpp
@@ -1225,6 +1237,44 @@
         return true;
     }
 
+    /**
+     * Poll for a timestamp on demand.
+     * <p>
+     * Same as {@link #getTimestamp(AudioTimestamp)} but with a more useful return code.
+     *
+     * @param timestamp a reference to a non-null AudioTimestamp instance allocated
+     *        and owned by caller.
+     * @return {@link #SUCCESS} if a timestamp is available
+     *         {@link #ERROR_WOULD_BLOCK} if called in STOPPED or FLUSHED state, or if called
+     *         immediately after start/ACTIVE, when the number of frames consumed is less than the
+     *         overall hardware latency to physical output. In WOULD_BLOCK cases, one might poll
+     *         again, or use {@link #getPlaybackHeadPosition}, or use 0 position and current time
+     *         for the timestamp.
+     *         {@link #ERROR_DEAD_OBJECT} if the AudioTrack is not valid anymore and
+     *         needs to be recreated.
+     *         {@link #ERROR_INVALID_OPERATION} if current route does not support
+     *         timestamps. In this case, the approximate frame position can be obtained
+     *         using {@link #getPlaybackHeadPosition}.
+     *
+     *         The AudioTimestamp instance is filled in with a position in frame units, together
+     *         with the estimated time when that frame was presented or is committed to
+     *         be presented.
+     * @hide
+     */
+     // Add this text when the "on new timestamp" API is added:
+     //   Use if you need to get the most recent timestamp outside of the event callback handler.
+     public int getTimestampWithStatus(AudioTimestamp timestamp)
+     {
+         if (timestamp == null) {
+             throw new IllegalArgumentException();
+         }
+         // It's unfortunate, but we have to either create garbage every time or use synchronized
+         long[] longArray = new long[2];
+         int ret = native_get_timestamp(longArray);
+         timestamp.framePosition = longArray[0];
+         timestamp.nanoTime = longArray[1];
+         return ret;
+     }
 
     //--------------------------------------------------------------------------
     // Initialization / configuration
diff --git a/media/java/android/media/midi/MidiManager.java b/media/java/android/media/midi/MidiManager.java
index 7197dc0..e72bdb4 100644
--- a/media/java/android/media/midi/MidiManager.java
+++ b/media/java/android/media/midi/MidiManager.java
@@ -288,7 +288,6 @@
                         // fetch MidiDeviceInfo from the server
                         MidiDeviceInfo deviceInfo = server.getDeviceInfo();
                         device = new MidiDevice(deviceInfo, server, mService, mToken, deviceToken);
-                        sendOpenDeviceResponse(device, listenerF, handlerF);
                     } catch (RemoteException e) {
                         Log.e(TAG, "remote exception in getDeviceInfo()");
                     }
diff --git a/media/java/android/media/midi/package.html b/media/java/android/media/midi/package.html
index 7baa5bc..45fb579 100644
--- a/media/java/android/media/midi/package.html
+++ b/media/java/android/media/midi/package.html
@@ -202,11 +202,12 @@
 <p>MIDI messages are sent as byte arrays. Here we encode a NoteOn message.</p>
 
 <pre class=prettyprint>
-byte[] buffer = new buffer[64];
+byte[] buffer = new byte[32];
 int numBytes = 0;
-buffer[numBytes++] = 0x90 + channel; // note on
-buffer[numBytes++] = pitch;
-buffer[numBytes++] = velocity;
+int channel = 3; // MIDI channels 1-16 are encoded as 0-15.
+buffer[numBytes++] = (byte)(0x90 + (channel - 1)); // note on
+buffer[numBytes++] = (byte)60; // pitch is middle C
+buffer[numBytes++] = (byte)127; // max velocity
 int offset = 0;
 // post is non-blocking
 inputPort.send(buffer, offset, numBytes);
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 d2824b5..a080c73 100644
--- a/media/java/android/mtp/MtpObjectInfo.java
+++ b/media/java/android/mtp/MtpObjectInfo.java
@@ -256,7 +256,7 @@
     /**
      * Builds a new object info instance.
      */
-    public class Builder {
+    public static class Builder {
         private MtpObjectInfo mObjectInfo;
 
         public Builder() {
@@ -273,25 +273,25 @@
         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 setAssociationDesc(int value) {
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index ad804f3..2a46ee7 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -412,30 +412,27 @@
 }
 
 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
 android_mtp_MtpDevice_send_object_info(JNIEnv *env, jobject thiz, jobject info)
 {
     MtpDevice* device = get_device_from_object(env, thiz);
-    if (!device)
+    if (!device) {
         return JNI_FALSE;
+    }
 
     // Updating existing objects is not supported.
-    if (env->GetIntField(info, field_objectInfo_handle) != -1)
+    if (env->GetIntField(info, field_objectInfo_handle) != -1) {
         return JNI_FALSE;
+    }
 
     MtpObjectInfo* object_info = new MtpObjectInfo(-1);
     object_info->mStorageID = env->GetIntField(info, field_objectInfo_storageId);
@@ -456,17 +453,21 @@
     object_info->mSequenceNumber = env->GetIntField(info, field_objectInfo_sequenceNumber);
 
     jstring name_jstring = (jstring) env->GetObjectField(info, field_objectInfo_name);
-    const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
-    object_info->mName = strdup(name_string);
-    env->ReleaseStringUTFChars(name_jstring, name_string);
+    if (name_jstring != NULL) {
+        const char* name_string = env->GetStringUTFChars(name_jstring, NULL);
+        object_info->mName = strdup(name_string);
+        env->ReleaseStringUTFChars(name_jstring, name_string);
+    }
 
     object_info->mDateCreated = env->GetLongField(info, field_objectInfo_dateCreated) / 1000LL;
     object_info->mDateModified = env->GetLongField(info, field_objectInfo_dateModified) / 1000LL;
 
     jstring keywords_jstring = (jstring) env->GetObjectField(info, field_objectInfo_keywords);
-    const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
-    object_info->mKeywords = strdup(keywords_string);
-    env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+    if (keywords_jstring != NULL) {
+        const char* keywords_string = env->GetStringUTFChars(keywords_jstring, NULL);
+        object_info->mKeywords = strdup(keywords_string);
+        env->ReleaseStringUTFChars(keywords_jstring, keywords_string);
+    }
 
     int object_handle = device->sendObjectInfo(object_info);
     if (object_handle == -1) {
@@ -510,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/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
index fbde2b4..1f81a05 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiService.java
@@ -46,6 +46,7 @@
                 device = mDeviceServerMap.get(bluetoothDevice);
                 if (device == null) {
                     device = new BluetoothMidiDevice(this, bluetoothDevice, this);
+                    mDeviceServerMap.put(bluetoothDevice, device);
                 }
             }
             return device.getBinder();
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..c21c5cc 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -5,9 +5,25 @@
 
 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
+LOCAL_RESOURCE_DIR += frameworks/support/design/res
+
+# Again, required to pull in appcompat resources.  See abovementioned demo code.
+LOCAL_AAPT_FLAGS := --auto-add-overlay
+LOCAL_AAPT_FLAGS += --extra-packages android.support.v7.appcompat
+LOCAL_AAPT_FLAGS += --extra-packages android.support.design
 
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index a0e3868..d578769 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -48,8 +48,8 @@
         </activity>
 
         <activity
-            android:name=".StandaloneActivity"
-            android:theme="@style/StandaloneTheme"
+            android:name=".FilesActivity"
+            android:theme="@style/FilesTheme"
             android:icon="@drawable/ic_files_app"
             android:label="@string/files_label"
             android:enabled="@bool/productivity_device">
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
similarity index 100%
rename from packages/DocumentsUI/res/layout/activity.xml
rename to packages/DocumentsUI/res/layout/drawer_layout.xml
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
similarity index 96%
rename from packages/DocumentsUI/res/layout-sw720dp/activity.xml
rename to packages/DocumentsUI/res/layout/fixed_layout.xml
index 221de13..9769f26 100644
--- a/packages/DocumentsUI/res/layout-sw720dp/activity.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/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 1001e10..71e618b 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/grid_item_height"
     android:layout_margin="@dimen/grid_item_margin"
@@ -140,4 +140,4 @@
         android:contentDescription="@null"
         android:duplicateParentState="true" />
 
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_loading_grid.xml b/packages/DocumentsUI/res/layout/item_loading_grid.xml
index 005a111..147dfd4 100644
--- a/packages/DocumentsUI/res/layout/item_loading_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_loading_grid.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/grid_height"
     android:orientation="horizontal">
@@ -26,4 +26,4 @@
         android:indeterminate="true"
         style="?android:attr/progressBarStyle" />
 
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/layout/item_message_grid.xml b/packages/DocumentsUI/res/layout/item_message_grid.xml
index 385563d..45d61a5 100644
--- a/packages/DocumentsUI/res/layout/item_message_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_message_grid.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.documentsui.GridItem xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="@dimen/grid_height"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
@@ -48,4 +48,4 @@
 
     </LinearLayout>
 
-</FrameLayout>
+</com.android.documentsui.GridItem>
diff --git a/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml b/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml
new file mode 100644
index 0000000..0e1807c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp-land/layouts.xml
@@ -0,0 +1,19 @@
+<?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>
+    <item name="files_activity" type="layout">@layout/fixed_layout</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values-sw720dp/layouts.xml b/packages/DocumentsUI/res/values-sw720dp/layouts.xml
new file mode 100644
index 0000000..7d28f9c
--- /dev/null
+++ b/packages/DocumentsUI/res/values-sw720dp/layouts.xml
@@ -0,0 +1,19 @@
+<?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>
+    <item name="docs_activity" type="layout">@layout/fixed_layout</item>
+</resources>
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/layouts.xml b/packages/DocumentsUI/res/values/layouts.xml
new file mode 100644
index 0000000..c73a1cb
--- /dev/null
+++ b/packages/DocumentsUI/res/values/layouts.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <item name="docs_activity" type="layout">@layout/drawer_layout</item>
+    <item name="files_activity" type="layout">@layout/drawer_layout</item>
+</resources>
diff --git a/packages/DocumentsUI/res/values/styles.xml b/packages/DocumentsUI/res/values/styles.xml
index 95c1d9c..f6c4628 100644
--- a/packages/DocumentsUI/res/values/styles.xml
+++ b/packages/DocumentsUI/res/values/styles.xml
@@ -16,12 +16,12 @@
 
 <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="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">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
+        <item name="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>
@@ -37,14 +37,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">@*android:style/ThemeOverlay.Material.Dark.ActionBar</item>
+        <item name="actionBarPopupTheme">@*android:style/ThemeOverlay.Material.Light</item>
 
         <item name="android:listDivider">@*android:drawable/list_divider_material</item>
 
@@ -55,6 +51,12 @@
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
     </style>
 
+    <style name="DocumentsNonDialogTheme" parent="@style/DocumentsBaseTheme.FullScreen">
+        <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>
+
     <style name="ActionModeStyle" parent="@android:style/Widget.Material.Light.ActionMode">
         <item name="android:background">@color/material_grey_600</item>
     </style>
@@ -63,21 +65,12 @@
         <item name="android:colorAccent">@color/material_blue_700</item>
     </style>
 
-    <style name="StandaloneTheme" parent="@android:style/Theme.Material.DayNight.DarkActionBar">
-        <item name="android:actionBarWidgetTheme">@null</item>
-
+    <style name="FilesTheme" parent="@style/DocumentsBaseTheme.FullScreen">
         <item name="android:colorPrimaryDark">@color/status_bar_background</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/BandSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java
deleted file mode 100644
index 74170f5..0000000
--- a/packages/DocumentsUI/src/com/android/documentsui/BandSelectManager.java
+++ /dev/null
@@ -1,335 +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.documentsui;
-
-import static com.android.documentsui.Events.isMouseEvent;
-import static com.android.internal.util.Preconditions.checkState;
-
-import android.graphics.Point;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.support.v7.widget.RecyclerView;
-import android.support.v7.widget.RecyclerView.ViewHolder;
-import android.util.Log;
-import android.util.SparseBooleanArray;
-import android.view.MotionEvent;
-import android.view.View;
-
-/**
- * Provides mouse driven band-select support when used in conjuction with {@link RecyclerView} and
- * {@link MultiSelectManager}. This class is responsible for rendering the band select overlay and
- * selecting overlaid items via MultiSelectManager.
- */
-public class BandSelectManager extends RecyclerView.SimpleOnItemTouchListener {
-
-    private static final int NOT_SELECTED = -1;
-    private static final int NOT_SET = -1;
-
-    // For debugging purposes.
-    private static final String TAG = "BandSelectManager";
-    private static final boolean DEBUG = false;
-
-    private final RecyclerView mRecyclerView;
-    private final MultiSelectManager mSelectManager;
-    private final Drawable mRegionSelectorDrawable;
-    private final SparseBooleanArray mSelectedByBand = new SparseBooleanArray();
-
-    private boolean mIsBandSelectActive = false;
-    private Point mOrigin;
-    private Point mPointer;
-    private Rect mBounds;
-
-    // Maintain the last selection made by band, so if bounds shrink back, we can deselect
-    // the respective items.
-    private int mCursorDeltaY = 0;
-    private int mFirstSelected = NOT_SELECTED;
-
-    // The time at which the current band selection-induced scroll began. If no scroll is in
-    // progress, the value is NOT_SET.
-    private long mScrollStartTime = NOT_SET;
-    private final Runnable mScrollRunnable = new Runnable() {
-        /**
-         * The number of milliseconds of scrolling at which scroll speed continues to increase. At
-         * first, the scroll starts slowly; then, the rate of scrolling increases until it reaches
-         * its maximum value at after this many milliseconds.
-         */
-        private static final long SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
-
-        @Override
-        public void run() {
-            // Compute the number of pixels the pointer's y-coordinate is past the view. Negative
-            // values mean the pointer is at or before the top of the view, and positive values mean
-            // that the pointer is at or after the bottom of the view. Note 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 >= mRecyclerView.getHeight() - 1) {
-                pixelsPastView = mPointer.y - mRecyclerView.getHeight() + 1;
-            }
-
-            if (!mIsBandSelectActive || 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;
-                return;
-            }
-
-            if (mScrollStartTime == NOT_SET) {
-                // If the pointer was previously not at the edge of the view but now is, set the
-                // start time for the scroll.
-                mScrollStartTime = System.currentTimeMillis();
-            }
-
-            // Compute the number of pixels to scroll, and scroll that many pixels.
-            final int numPixels = computeNumPixelsToScroll(
-                    pixelsPastView, System.currentTimeMillis() - mScrollStartTime);
-            mRecyclerView.scrollBy(0, numPixels);
-
-            // Adjust the y-coordinate of the origin the opposite number of pixels so that the
-            // origin remains in the same place relative to the view's items.
-            mOrigin.y -= numPixels;
-            resizeBandSelectRectangle();
-
-            mRecyclerView.removeCallbacks(mScrollRunnable);
-            mRecyclerView.postOnAnimation(this);
-        }
-
-        /**
-         * Computes the number of pixels to scroll based on how far the pointer is past the end of
-         * the view and how long it has been there. Roughly based on ItemTouchHelper's algorithm for
-         * computing the number of pixels to scroll when an item is dragged to the end of a
-         * {@link RecyclerView}.
-         * @param pixelsPastView
-         * @param scrollDuration
-         * @return
-         */
-        private int computeNumPixelsToScroll(int pixelsPastView, long scrollDuration) {
-            final int maxScrollStep = computeMaxScrollStep(mRecyclerView);
-            final int direction = (int) Math.signum(pixelsPastView);
-            final int absPastView = Math.abs(pixelsPastView);
-
-            // Calculate the ratio of how far out of the view the pointer currently resides to the
-            // entire height of the view.
-            final float outOfBoundsRatio = Math.min(
-                    1.0f, (float) absPastView / mRecyclerView.getHeight());
-            // Interpolate this ratio and use it to compute the maximum scroll that should be
-            // possible for this step.
-            final float cappedScrollStep =
-                    direction * maxScrollStep * smoothOutOfBoundsRatio(outOfBoundsRatio);
-
-            // Likewise, calculate the ratio of the time spent in the scroll to the limit.
-            final float timeRatio = Math.min(
-                    1.0f, (float) scrollDuration / SCROLL_ACCELERATION_LIMIT_TIME_MS);
-            // Interpolate this ratio and use it to compute the final number of pixels to scroll.
-            final int numPixels = (int) (cappedScrollStep * smoothTimeRatio(timeRatio));
-
-            // If the final number of pixels to scroll ends up being 0, the view should still scroll
-            // at least one pixel.
-            return numPixels != 0 ? numPixels : direction;
-        }
-
-        /**
-         * Computes the maximum scroll allowed for a given animation frame. Currently, this
-         * defaults to the height of the view, but this could be tweaked if this results in scrolls
-         * that are too fast or too slow.
-         * @param rv
-         * @return
-         */
-        private int computeMaxScrollStep(RecyclerView rv) {
-            return rv.getHeight();
-        }
-
-        /**
-         * Interpolates the given out of bounds ratio on a curve which starts at (0,0) and ends at
-         * (1,1) and quickly approaches 1 near the start of that interval. This ensures that drags
-         * that are at the edge or barely past the edge of the view still cause sufficient
-         * scrolling. The equation y=(x-1)^5+1 is used, but this could also be tweaked if needed.
-         * @param ratio A ratio which is in the range [0, 1].
-         * @return A "smoothed" value, also in the range [0, 1].
-         */
-        private float smoothOutOfBoundsRatio(float ratio) {
-            return (float) Math.pow(ratio - 1.0f, 5) + 1.0f;
-        }
-
-        /**
-         * Interpolates the given time ratio on a curve which starts at (0,0) and ends at (1,1) and
-         * stays close to 0 for most input values except those very close to 1. This ensures that
-         * scrolls start out very slowly but speed up drastically after the scroll has been in
-         * progress close to SCROLL_ACCELERATION_LIMIT_TIME_MS. The equation y=x^5 is used, but this
-         * could also be tweaked if needed.
-         * @param ratio A ratio which is in the range [0, 1].
-         * @return A "smoothed" value, also in the range [0, 1].
-         */
-        private float smoothTimeRatio(float ratio) {
-            return (float) Math.pow(ratio, 5);
-        }
-    };
-
-    /**
-     * @param recyclerView
-     * @param multiSelectManager
-     */
-    public BandSelectManager(RecyclerView recyclerView, MultiSelectManager multiSelectManager) {
-        mRecyclerView = recyclerView;
-        mSelectManager = multiSelectManager;
-        mRegionSelectorDrawable =
-            mRecyclerView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
-
-        mRecyclerView.addOnItemTouchListener(this);
-    }
-
-    @Override
-    public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
-        // Only intercept the event if it was triggered by a mouse. If band select is inactive,
-        // do not intercept ACTION_UP events as they will not be processed.
-        return isMouseEvent(e) &&
-                (mIsBandSelectActive || e.getActionMasked() != MotionEvent.ACTION_UP);
-    }
-
-    @Override
-    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
-        checkState(isMouseEvent(e));
-        processMotionEvent(e);
-    }
-
-    /**
-     * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
-     * @param e
-     */
-    private void processMotionEvent(MotionEvent e) {
-        if (mIsBandSelectActive && e.getActionMasked() == MotionEvent.ACTION_UP) {
-            endBandSelect();
-            return;
-        }
-
-        mPointer = new Point((int) e.getX(), (int) e.getY());
-        if (!mIsBandSelectActive) {
-            startBandSelect();
-        }
-
-        scrollViewIfNecessary();
-        resizeBandSelectRectangle();
-        selectChildrenCoveredBySelection();
-    }
-
-    /**
-     * 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 + ").");
-        mIsBandSelectActive = true;
-        mOrigin = mPointer;
-        mRecyclerView.getOverlay().add(mRegionSelectorDrawable);
-    }
-
-    /**
-     * Scrolls the view if necessary.
-     */
-    private void scrollViewIfNecessary() {
-        mRecyclerView.removeCallbacks(mScrollRunnable);
-        mScrollRunnable.run();
-        mRecyclerView.invalidate();
-    }
-
-    /**
-     * Resizes the band select rectangle by using the origin and the current pointer positoin as
-     * two opposite corners of the selection.
-     */
-    private void resizeBandSelectRectangle() {
-        if (mBounds != null) {
-            mCursorDeltaY = mPointer.y - mBounds.bottom;
-        }
-
-        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));
-
-        mRegionSelectorDrawable.setBounds(mBounds);
-    }
-
-    /**
-     * Selects the children covered by the band select overlay by delegating to MultiSelectManager.
-     * TODO: Provide a finished implementation. This is down and dirty, proof of concept code.
-     * Final optimized implementation, with support for managing offscreen selection to come.
-     */
-    private void selectChildrenCoveredBySelection() {
-
-        // track top and bottom selections. Details on why this is useful below.
-        int first = NOT_SELECTED;
-        int last = NOT_SELECTED;
-
-        for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
-
-            View child = mRecyclerView.getChildAt(i);
-            ViewHolder holder = mRecyclerView.getChildViewHolder(child);
-            Rect childRect = new Rect();
-            child.getHitRect(childRect);
-
-            boolean shouldSelect = Rect.intersects(childRect, mBounds);
-            int position = holder.getAdapterPosition();
-
-            // This also allows us to clear the selection of elements
-            // that only temporarily entered the bounds of the band.
-            if (mSelectedByBand.get(position) && !shouldSelect) {
-                mSelectManager.setItemSelected(position, false);
-                mSelectedByBand.delete(position);
-            }
-
-            // We need to keep track of the first and last items selected.
-            // We'll use this information along with cursor direction
-            // to determine the starting point of the selection.
-            // We provide this information to selection manager
-            // to enable more natural user interaction when working
-            // with Shift+Click and multiple contiguous selection ranges.
-            if (shouldSelect) {
-                if (first == NOT_SELECTED) {
-                    first = position;
-                } else {
-                    last = position;
-                }
-                mSelectManager.setItemSelected(position, true);
-                mSelectedByBand.put(position, true);
-            }
-        }
-
-        // Remember which is the last selected item, so we can
-        // share that with selection manager when band select ends.
-        // It'll use that as it's begin selection point when
-        // user SHIFT+Clicks.
-        if (mCursorDeltaY < 0 && last != NOT_SELECTED) {
-            mFirstSelected = last;
-        } else if (mCursorDeltaY > 0 && first != NOT_SELECTED) {
-            mFirstSelected = first;
-        }
-    }
-
-    /**
-     * Ends band select by removing the overlay.
-     */
-    private void endBandSelect() {
-        if (DEBUG) Log.d(TAG, "Ending band select.");
-        mIsBandSelectActive = false;
-        mSelectedByBand.clear();
-        mRecyclerView.getOverlay().remove(mRegionSelectorDrawable);
-        if (mFirstSelected != NOT_SELECTED) {
-            mSelectManager.setSelectionFocusBegin(mFirstSelected);
-        }
-    }
-}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 9b8d847..2835106 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -22,7 +22,6 @@
 import static com.android.documentsui.DirectoryFragment.ANIM_UP;
 import static com.android.internal.util.Preconditions.checkArgument;
 
-import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.Fragment;
 import android.content.Intent;
@@ -38,6 +37,8 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.support.annotation.LayoutRes;
+import android.support.annotation.Nullable;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.LayoutInflater;
@@ -46,6 +47,7 @@
 import android.view.MenuItem.OnActionExpandListener;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewStub;
 import android.widget.AdapterView;
 import android.widget.AdapterView.OnItemSelectedListener;
 import android.widget.BaseAdapter;
@@ -60,8 +62,6 @@
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
 
-import com.google.common.collect.Maps;
-
 import libcore.io.IoUtils;
 
 import java.io.FileNotFoundException;
@@ -76,9 +76,13 @@
 
     static final String EXTRA_STATE = "state";
 
+    State mState;
     RootsCache mRoots;
     SearchManager mSearchManager;
+    DrawerController mDrawer;
 
+    @LayoutRes
+    private int mLayoutId;
     private final String mTag;
 
     public abstract State getDisplayState();
@@ -89,16 +93,28 @@
     abstract void onDirectoryChanged(int anim);
     abstract void updateActionBar();
     abstract void saveStackBlocking();
+    abstract State buildDefaultState();
 
-    public BaseActivity(String tag) {
+    public BaseActivity(@LayoutRes int layoutId, String tag) {
+        mLayoutId = layoutId;
         mTag = tag;
     }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
+
+        mState = (icicle != null)
+                ? icicle.<State>getParcelable(EXTRA_STATE)
+                        : buildDefaultState();
+
+        setContentView(mLayoutId);
+
         mRoots = DocumentsApplication.getRootsCache(this);
         mSearchManager = new SearchManager();
+
+        // Base classes must update result in their onCreate.
+        setResult(Activity.RESULT_CANCELED);
     }
 
     @Override
@@ -371,7 +387,7 @@
         public String currentSearch;
 
         /** Instance state for every shown directory */
-        public HashMap<String, SparseArray<Parcelable>> dirState = Maps.newHashMap();
+        public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
 
         /** Currently copying file */
         public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
@@ -527,6 +543,30 @@
         }
     }
 
+    @Override
+    public void onBackPressed() {
+        // While action bar is expanded, the state stack UI is hidden.
+        if (mSearchManager.cancelSearch()) {
+            return;
+        }
+
+        if (!mState.stackTouched) {
+            super.onBackPressed();
+            return;
+        }
+
+        final int size = mState.stack.size();
+
+        if (mDrawer.isOpen()) {
+            mDrawer.setOpen(false);
+        } else if (size > 1) {
+            mState.stack.pop();
+            onCurrentDirectoryChanged(ANIM_UP);
+        } else {
+            super.onBackPressed();
+        }
+    }
+
     public void onStackPicked(DocumentStack stack) {
         try {
             // Update the restored stack to ensure we have freshest data
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index 14155d5..8b92331 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -167,7 +167,7 @@
 
             if (mFailedFiles.size() > 0) {
                 final Context context = getApplicationContext();
-                final Intent navigateIntent = new Intent(context, StandaloneActivity.class);
+                final Intent navigateIntent = new Intent(context, FilesActivity.class);
                 navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
                 navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY);
                 navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles);
@@ -213,7 +213,7 @@
         mIsCancelled = false;
 
         final Context context = getApplicationContext();
-        final Intent navigateIntent = new Intent(context, StandaloneActivity.class);
+        final Intent navigateIntent = new Intent(context, FilesActivity.class);
         navigateIntent.putExtra(EXTRA_STACK, (Parcelable) stack);
 
         final String contentTitle = getString(copying ? R.string.copy_notification_title
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index f927595..e408e6e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -36,7 +36,6 @@
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 5223d76..c28806b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -24,14 +24,13 @@
 import static com.android.documentsui.BaseActivity.State.MODE_LIST;
 import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.Preconditions.checkState;
 
-import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.Fragment;
@@ -98,7 +97,7 @@
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.util.Preconditions;
 
-import com.google.android.collect.Lists;
+import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -235,8 +234,7 @@
                     public void onLayoutChange(
                             View v, int left, int top, int right, int bottom, int oldLeft,
                             int oldTop, int oldRight, int oldBottom) {
-                        int thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width);
-                        mColumnCount = pickColumnCount(thumbSize);
+                        mColumnCount = calculateColumnCount();
                         if (mGridLayout != null) {
                             mGridLayout.setSpanCount(mColumnCount);
                         }
@@ -535,8 +533,6 @@
 
         updateLayout(state.derivedMode);
 
-        final int thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
-        mThumbSize = new Point(thumbSize, thumbSize);
         mRecView.setAdapter(mAdapter);
     }
 
@@ -573,13 +569,15 @@
         mThumbSize = new Point(thumbSize, thumbSize);
     }
 
-    private int pickColumnCount(final int thumbSize) {
-        int itemPadding =
-                getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
+    private int calculateColumnCount() {
+        int cellWidth = getResources().getDimensionPixelSize(R.dimen.grid_width);
+        int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
         int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
+
         checkState(mRecView.getWidth() > 0);
         int columnCount = Math.max(1,
-                (mRecView.getWidth() - viewPadding) / (thumbSize + itemPadding));
+                (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
+
         return columnCount;
     }
 
@@ -740,7 +738,7 @@
         new GetDocumentsTask() {
             @Override
             void onDocumentsReady(List<DocumentInfo> docs) {
-                // TODO: Implement support in standalone for opening multiple docs.
+                // TODO: Implement support in Files activity for opening multiple docs.
                 BaseActivity.get(DirectoryFragment.this).onDocumentsPicked(docs);
             }
         }.execute(selected);
@@ -753,7 +751,7 @@
                 Intent intent;
 
                 // Filter out directories - those can't be shared.
-                List<DocumentInfo> docsForSend = Lists.newArrayList();
+                List<DocumentInfo> docsForSend = new ArrayList<>();
                 for (DocumentInfo doc: docs) {
                     if (!Document.MIME_TYPE_DIR.equals(doc.mimeType)) {
                         docsForSend.add(doc);
@@ -774,8 +772,8 @@
                     intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                     intent.addCategory(Intent.CATEGORY_DEFAULT);
 
-                    final ArrayList<String> mimeTypes = Lists.newArrayList();
-                    final ArrayList<Uri> uris = Lists.newArrayList();
+                    final ArrayList<String> mimeTypes = new ArrayList<>();
+                    final ArrayList<Uri> uris = new ArrayList<>();
                     for (DocumentInfo doc : docsForSend) {
                         mimeTypes.add(doc.mimeType);
                         uris.add(doc.derivedUri);
@@ -956,7 +954,7 @@
         private final Context mContext;
         private final LayoutInflater mInflater;
         // TODO: Bring back support for footers.
-        private final List<Footer> mFooters = Lists.newArrayList();
+        private final List<Footer> mFooters = new ArrayList<>();
 
         private Cursor mCursor;
         private int mCursorCount;
@@ -1330,7 +1328,7 @@
         return MimePredicate.mimeMatches(state.acceptMimes, docMimeType);
     }
 
-    private @NonNull List<DocumentInfo> getSelectedDocuments() {
+    private List<DocumentInfo> getSelectedDocuments() {
         Selection sel = mSelectionManager.getSelection(new Selection());
         return getItemsAsDocuments(sel);
     }
@@ -1570,6 +1568,7 @@
         final Cursor cursor = mAdapter.getItem(position);
         checkNotNull(cursor, "Cursor cannot be null.");
         final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
+
         return Lists.newArrayList(doc);
     }
 
@@ -1685,7 +1684,7 @@
 
     private FragmentTuner pickFragmentTuner(final State state) {
         return state.action == ACTION_BROWSE_ALL
-                ? new StandaloneTuner()
+                ? new FilesTuner()
                 : new DefaultTuner(state);
     }
 
@@ -1750,7 +1749,7 @@
             copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN);
             moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
 
-            // Only shown in standalone mode.
+            // Only shown in files mode.
             copyToClipboard.setVisible(false);
         }
 
@@ -1759,9 +1758,9 @@
     }
 
     /**
-     * Provides support for Standalone specific specializations of DirectoryFragment.
+     * Provides support for Files activity specific specializations of DirectoryFragment.
      */
-    private static final class StandaloneTuner implements FragmentTuner {
+    private static final class FilesTuner implements FragmentTuner {
         @Override
         public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
             menu.findItem(R.id.menu_share).setVisible(true);
@@ -1774,8 +1773,6 @@
         }
 
         @Override
-        public void afterActivityCreated(DirectoryFragment fragment) {
-            new BandSelectManager(fragment.mRecView, fragment.mSelectionManager);
-        }
+        public void afterActivityCreated(DirectoryFragment fragment) {}
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index a8a61d2..0edb241 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
 import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 
 import android.content.AsyncTaskLoader;
@@ -31,8 +31,6 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.CancellationSignal;
-import android.os.Handler;
-import android.os.Looper;
 import android.os.OperationCanceledException;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 2370575..6ba07fbb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -16,8 +16,6 @@
 
 package com.android.documentsui;
 
-import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.ClipboardManager;
 import android.content.ContentProviderClient;
@@ -26,15 +24,15 @@
 import android.database.Cursor;
 import android.net.Uri;
 import android.provider.DocumentsContract;
+import android.support.annotation.Nullable;
 import android.util.Log;
 
 import com.android.documentsui.model.DocumentInfo;
 import com.android.internal.util.Preconditions;
 
-import com.google.android.collect.Lists;
-
 import libcore.io.IoUtils;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -78,7 +76,7 @@
      * Returns a list of Documents as decoded from Clipboard primary clipdata.
      * This should be run from inside an AsyncTask.
      */
-    public @NonNull List<DocumentInfo> getClippedDocuments() {
+    public List<DocumentInfo> getClippedDocuments() {
         return getDocumentsFromClipData(mClipboard.getPrimaryClip());
     }
 
@@ -86,9 +84,9 @@
      * Returns a list of Documents as decoded in clipData.
      * This should be run from inside an AsyncTask.
      */
-    public @NonNull List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
+    public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
         Preconditions.checkNotNull(clipData);
-        final List<DocumentInfo> srcDocs = Lists.newArrayList();
+        final List<DocumentInfo> srcDocs = new ArrayList<>();
 
         int count = clipData.getItemCount();
         if (count == 0) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 2de7fc4..fdc4bb0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -25,8 +25,6 @@
 import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
-import static com.android.documentsui.DirectoryFragment.ANIM_UP;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -48,9 +46,6 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
-import android.support.v4.app.ActionBarDrawerToggle;
-import android.support.v4.widget.DrawerLayout;
-import android.support.v4.widget.DrawerLayout.DrawerListener;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -81,42 +76,32 @@
 
     private Toolbar mRootsToolbar;
 
-    private DrawerLayout mDrawerLayout;
-    private ActionBarDrawerToggle mDrawerToggle;
-    private View mRootsDrawer;
-
     private DirectoryContainerView mDirectoryContainer;
 
-    private State mState;
-
     private ItemSelectedListener mStackListener;
     private BaseAdapter mStackAdapter;
 
     public DocumentsActivity() {
-        super(TAG);
+        super(R.layout.docs_activity, TAG);
     }
 
     @Override
     public void onCreate(Bundle icicle) {
-        mState = (icicle != null)
-                ? icicle.<State>getParcelable(EXTRA_STATE)
-                : buildDefaultState();
+        super.onCreate(icicle);
 
         final Resources res = getResources();
         mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_MANAGE &&
                 mState.action != ACTION_BROWSE;
+
         if (!mShowAsDialog) {
             setTheme(R.style.DocumentsNonDialogTheme);
         }
 
-        super.onCreate(icicle);
-
-        setResult(Activity.RESULT_CANCELED);
-        setContentView(R.layout.activity);
-
         final Context context = this;
 
         if (mShowAsDialog) {
+            mDrawer = DrawerController.createDummy();
+
             // Strongly define our horizontal dimension; we leave vertical as
             // WRAP_CONTENT so that system resizes us when IME is showing.
             final WindowManager.LayoutParams a = getWindow().getAttributes();
@@ -128,17 +113,7 @@
             getWindow().setAttributes(a);
 
         } else {
-            // Non-dialog means we have a drawer
-            mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
-
-            if (mDrawerLayout != null) {
-                mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
-                        R.drawable.ic_hamburger, R.string.drawer_open, R.string.drawer_close);
-
-                mDrawerLayout.setDrawerListener(mDrawerListener);
-
-                mRootsDrawer = findViewById(R.id.drawer_roots);
-            }
+            mDrawer = DrawerController.create(this);
         }
 
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
@@ -162,10 +137,9 @@
 
         // Hide roots when we're managing a specific root
         if (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE) {
-            if (mShowAsDialog || mDrawerLayout == null) {
+            mDrawer.lockClosed();
+            if (mShowAsDialog) {
                 findViewById(R.id.container_roots).setVisibility(View.GONE);
-            } else {
-                mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
             }
         }
 
@@ -205,7 +179,8 @@
         }
     }
 
-    private State buildDefaultState() {
+    @Override
+    State buildDefaultState() {
         State state = new State();
 
         final Intent intent = getIntent();
@@ -341,53 +316,15 @@
         }
     }
 
-    private DrawerListener mDrawerListener = new DrawerListener() {
-        @Override
-        public void onDrawerSlide(View drawerView, float slideOffset) {
-            mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
-        }
-
-        @Override
-        public void onDrawerOpened(View drawerView) {
-            mDrawerToggle.onDrawerOpened(drawerView);
-        }
-
-        @Override
-        public void onDrawerClosed(View drawerView) {
-            mDrawerToggle.onDrawerClosed(drawerView);
-        }
-
-        @Override
-        public void onDrawerStateChanged(int newState) {
-            mDrawerToggle.onDrawerStateChanged(newState);
-        }
-    };
-
     @Override
     protected void onPostCreate(Bundle savedInstanceState) {
         super.onPostCreate(savedInstanceState);
-        if (mDrawerToggle != null) {
-            mDrawerToggle.syncState();
-        }
+        mDrawer.syncState();
         updateActionBar();
     }
 
     public void setRootsDrawerOpen(boolean open) {
-        if (!mShowAsDialog && mDrawerLayout != null) {
-            if (open) {
-                mDrawerLayout.openDrawer(mRootsDrawer);
-            } else {
-                mDrawerLayout.closeDrawer(mRootsDrawer);
-            }
-        }
-    }
-
-    private boolean isRootsDrawerOpen() {
-        if (mShowAsDialog || mDrawerLayout == null) {
-            return false;
-        } else {
-            return mDrawerLayout.isDrawerOpen(mRootsDrawer);
-        }
+        mDrawer.setOpen(open);
     }
 
     @Override
@@ -408,8 +345,7 @@
             }
         }
 
-        if (!mShowAsDialog && mDrawerLayout != null &&
-                mDrawerLayout.getDrawerLockMode(mRootsDrawer) == DrawerLayout.LOCK_MODE_UNLOCKED) {
+        if (!mShowAsDialog && mDrawer.isUnlocked()) {
             mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
             mToolbar.setNavigationContentDescription(R.string.drawer_open);
             mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
@@ -504,34 +440,7 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
-            return true;
-        }
-        return super.onOptionsItemSelected(item);
-    }
-
-    @Override
-    public void onBackPressed() {
-        // While action bar is expanded, the state stack UI is hidden.
-        if (mSearchManager.cancelSearch()) {
-            return;
-        }
-
-        if (!mState.stackTouched) {
-            super.onBackPressed();
-            return;
-        }
-
-        final int size = mState.stack.size();
-        if (size > 1) {
-            mState.stack.pop();
-            onCurrentDirectoryChanged(ANIM_UP);
-        } else if (size == 1 && !isRootsDrawerOpen()) {
-            // TODO: open root drawer once we can capture back key
-            super.onBackPressed();
-        } else {
-            super.onBackPressed();
-        }
+        return mDrawer.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
new file mode 100644
index 0000000..df3ac1b
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
@@ -0,0 +1,207 @@
+/*
+ * 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.documentsui;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.app.Activity;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.widget.DrawerLayout;
+import android.support.v4.widget.DrawerLayout.DrawerListener;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * A facade over the various pieces comprising "roots fragment in a Drawer".
+ *
+ * @see DrawerController#create(DrawerLayout)
+ */
+abstract class DrawerController implements DrawerListener {
+
+    abstract void setOpen(boolean open);
+    abstract void lockOpen();
+    abstract void lockClosed();
+    abstract boolean isPresent();
+    abstract boolean isOpen();
+    abstract boolean isUnlocked();
+    abstract void syncState();
+    abstract boolean onOptionsItemSelected(MenuItem item);
+
+    /**
+     * Returns a controller suitable for {@code Layout}.
+     */
+    static DrawerController create(Activity activity) {
+
+        DrawerLayout layout = (DrawerLayout) activity.findViewById(R.id.drawer_layout);
+
+        if (layout == null) {
+            return new DummyDrawerController();
+        }
+
+        View drawer = activity.findViewById(R.id.drawer_roots);
+        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
+                activity,
+                layout,
+                R.drawable.ic_hamburger,
+                R.string.drawer_open,
+                R.string.drawer_close);
+
+        return new RuntimeDrawerController(layout, drawer, toggle);
+    }
+
+    /**
+     * Returns a controller suitable for {@code Layout}.
+     */
+    static DrawerController createDummy() {
+        return new DummyDrawerController();
+    }
+
+    /**
+     * Runtime controller that manages a real drawer.
+     */
+    private static final class RuntimeDrawerController extends DrawerController {
+
+        private final ActionBarDrawerToggle mToggle;
+        private DrawerLayout mLayout;
+        private View mDrawer;
+
+        public RuntimeDrawerController(
+                DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle) {
+            checkArgument(layout != null);
+
+            mLayout = layout;
+            mDrawer = drawer;
+            mToggle = toggle;
+
+            mLayout.setDrawerListener(this);
+        }
+
+        @Override
+        void setOpen(boolean open) {
+            if (open) {
+                mLayout.openDrawer(mDrawer);
+            } else {
+                mLayout.closeDrawer(mDrawer);
+            }
+        }
+
+        @Override
+        boolean isOpen() {
+            return mLayout.isDrawerOpen(mDrawer);
+        }
+
+        @Override
+        boolean isPresent() {
+            return true;
+        }
+
+        @Override
+        void syncState() {
+            mToggle.syncState();
+        }
+
+        @Override
+        boolean isUnlocked() {
+            return mLayout.getDrawerLockMode(mDrawer) == DrawerLayout.LOCK_MODE_UNLOCKED;
+        }
+
+        @Override
+        void lockOpen() {
+            mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_OPEN);
+        }
+
+        @Override
+        void lockClosed() {
+            mLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
+        }
+
+        @Override
+        boolean onOptionsItemSelected(MenuItem item) {
+            return false;
+        }
+
+        @Override
+        public void onDrawerSlide(View drawerView, float slideOffset) {
+            mToggle.onDrawerSlide(drawerView, slideOffset);
+        }
+
+        @Override
+        public void onDrawerOpened(View drawerView) {
+            mToggle.onDrawerOpened(drawerView);
+        }
+
+        @Override
+        public void onDrawerClosed(View drawerView) {
+            mToggle.onDrawerClosed(drawerView);
+        }
+
+        @Override
+        public void onDrawerStateChanged(int newState) {
+            mToggle.onDrawerStateChanged(newState);
+        }
+    }
+
+    /*
+     * Dummy controller useful with clients that don't host a real drawer.
+     */
+    private static final class DummyDrawerController extends DrawerController {
+
+        @Override
+        void setOpen(boolean open) {}
+
+        @Override
+        void syncState() {}
+
+        @Override
+        void lockOpen() {}
+
+        @Override
+        void lockClosed() {}
+
+        @Override
+        boolean isOpen() {
+            return false;
+        }
+
+        @Override
+        boolean isUnlocked() {
+            return true;
+        }
+
+        @Override
+        boolean isPresent() {
+            return false;
+        }
+
+        @Override
+        boolean onOptionsItemSelected(MenuItem item) {
+            return false;
+        }
+
+        @Override
+        public void onDrawerSlide(View drawerView, float slideOffset) {}
+
+        @Override
+        public void onDrawerOpened(View drawerView) {}
+
+        @Override
+        public void onDrawerClosed(View drawerView) {}
+
+        @Override
+        public void onDrawerStateChanged(int newState) {}
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
similarity index 91%
rename from packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
rename to packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 1ca277d..7c445bf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/StandaloneActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -18,9 +18,7 @@
 
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
-import static com.android.documentsui.DirectoryFragment.ANIM_UP;
 
-import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.FragmentManager;
 import android.content.ActivityNotFoundException;
@@ -33,6 +31,7 @@
 import android.os.Bundle;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.support.annotation.Nullable;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -57,7 +56,7 @@
 /**
  * Standalone file management activity.
  */
-public class StandaloneActivity extends BaseActivity {
+public class FilesActivity extends BaseActivity {
 
     public static final String TAG = "StandaloneFileManagement";
     static final boolean DEBUG = false;
@@ -66,30 +65,22 @@
     private Spinner mToolbarStack;
     private Toolbar mRootsToolbar;
     private DirectoryContainerView mDirectoryContainer;
-    private State mState;
     private ItemSelectedListener mStackListener;
     private BaseAdapter mStackAdapter;
     private DocumentClipper mClipper;
 
-    public StandaloneActivity() {
-        super(TAG);
+    public FilesActivity() {
+        super(R.layout.files_activity, TAG);
     }
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        setResult(Activity.RESULT_CANCELED);
-        setContentView(R.layout.activity);
-
         final Context context = this;
 
         mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
 
-        mState = (icicle != null)
-                ? icicle.<State> getParcelable(EXTRA_STATE)
-                : buildDefaultState();
-
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
         mToolbar.setTitleTextAppearance(context,
                 android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
@@ -108,6 +99,11 @@
         setActionBar(mToolbar);
 
         mClipper = new DocumentClipper(this);
+        mDrawer = DrawerController.create(this);
+        if (mDrawer.isPresent()) {
+            setTheme(R.style.DocumentsNonDialogTheme);
+        }
+
 
         RootsFragment.show(getFragmentManager(), null);
         if (!mState.restored) {
@@ -130,7 +126,8 @@
         }
     }
 
-    private State buildDefaultState() {
+    @Override
+    State buildDefaultState() {
         State state = new State();
 
         final Intent intent = getIntent();
@@ -164,10 +161,23 @@
     @Override
     public void updateActionBar() {
         final RootInfo root = getCurrentRoot();
-        mToolbar.setNavigationIcon(
-                root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
-        mToolbar.setNavigationContentDescription(R.string.drawer_open);
-        mToolbar.setNavigationOnClickListener(null);
+
+        if (mDrawer.isPresent()) {
+            mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
+            mToolbar.setNavigationContentDescription(R.string.drawer_open);
+            mToolbar.setNavigationOnClickListener(
+                    new View.OnClickListener() {
+                        @Override
+                        public void onClick(View v) {
+                            mDrawer.setOpen(true);
+                        }
+                    });
+        } else {
+            mToolbar.setNavigationIcon(
+                    root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
+            mToolbar.setNavigationContentDescription(R.string.drawer_open);
+            mToolbar.setNavigationOnClickListener(null);
+        }
 
         if (mSearchManager.isExpanded()) {
             mToolbar.setTitle(null);
@@ -236,22 +246,6 @@
     }
 
     @Override
-    public void onBackPressed() {
-        if (!mState.stackTouched) {
-            super.onBackPressed();
-            return;
-        }
-
-        final int size = mState.stack.size();
-        if (size > 1) {
-            mState.stack.pop();
-            onCurrentDirectoryChanged(ANIM_UP);
-        } else {
-            super.onBackPressed();
-        }
-    }
-
-    @Override
     public State getDisplayState() {
         return mState;
     }
@@ -284,6 +278,12 @@
     }
 
     @Override
+    void onRootPicked(RootInfo root) {
+        super.onRootPicked(root);
+        mDrawer.setOpen(false);
+    }
+
+    @Override
     public void onDocumentsPicked(List<DocumentInfo> docs) {
         throw new UnsupportedOperationException();
     }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
index 1cbc221..17a1161 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/GridItem.java b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
new file mode 100644
index 0000000..990dca7
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/GridItem.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+/**
+ * A FrameLayout subclass used by DirectoryFragment. Ensures that the resulting grid item is always
+ * square.
+ */
+public class GridItem extends FrameLayout {
+    public GridItem(Context context) {
+        super(context);
+    }
+
+    public GridItem(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public GridItem(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+    }
+
+    @Override
+    public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        // Grid layout uses item width to figure out the number of columns, then dynamically fits
+        // rows into the view. The upshot of this is that changing the item width will mess up the
+        // grid layout - so to make the items square, throw out the height and use the width for
+        // both dimensions. The grid layout will correctly adjust the row height.
+        //
+        // Note that this code will need to be changed if the layout manager's orientation is
+        // changed from VERTICAL to HORIZONTAL.
+        super.onMeasure(widthMeasureSpec, widthMeasureSpec);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index b43fedf..9959265 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -23,13 +23,11 @@
 import android.provider.DocumentsContract.Document;
 import android.util.TypedValue;
 
-import com.google.android.collect.Maps;
-
 import java.util.HashMap;
 
 public class IconUtils {
 
-    private static HashMap<String, Integer> sMimeIcons = Maps.newHashMap();
+    private static HashMap<String, Integer> sMimeIcons = new HashMap<>();
 
     private static void add(String mimeType, int resId) {
         if (sMimeIcons.put(mimeType, resId) != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 02edd0c..e972566 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -16,24 +16,33 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Events.isMouseEvent;
 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.support.v7.widget.GridLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.Adapter;
 import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.support.v7.widget.RecyclerView.LayoutManager;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.view.GestureDetector;
 import android.view.GestureDetector.OnDoubleTapListener;
 import android.view.GestureDetector.OnGestureListener;
 import android.view.MotionEvent;
 import android.view.View;
-
-import com.google.common.annotations.VisibleForTesting;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.VisibleForTesting;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -61,12 +70,13 @@
     private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
 
     private Adapter<?> mAdapter;
-    private RecyclerViewHelper mHelper;
+    private MultiSelectHelper mHelper;
     private boolean mSingleSelect;
+    private BandSelectManager mBandSelectManager;
 
     /**
      * @param recyclerView
-     * @param gestureDelegate Option delage gesture listener.
+     * @param gestureDelegate Option delegate gesture listener.
      * @param mode Selection mode
      * @template A gestureDelegate that implements both {@link OnGestureListener}
      *     and {@link OnDoubleTapListener}
@@ -76,17 +86,11 @@
 
         this(
                 recyclerView.getAdapter(),
-                new RecyclerViewHelper() {
-                    @Override
-                    public int findEventPosition(MotionEvent e) {
-                        View view = recyclerView.findChildViewUnder(e.getX(), e.getY());
-                        return view != null
-                                ? recyclerView.getChildAdapterPosition(view)
-                                : RecyclerView.NO_POSITION;
-                    }
-                },
+                new RuntimeRecyclerViewHelper(recyclerView),
                 mode);
 
+        mBandSelectManager = new BandSelectManager((RuntimeRecyclerViewHelper) mHelper);
+
         GestureDetector.SimpleOnGestureListener listener =
                 new GestureDetector.SimpleOnGestureListener() {
                     @Override
@@ -101,11 +105,8 @@
 
         CompositeOnGestureListener<? extends Object> compositeListener =
                 new CompositeOnGestureListener<>(listener, gestureDelegate);
-        final GestureDetector detector = new GestureDetector(
-                recyclerView.getContext(),
-                gestureDelegate == null
-                        ? listener
-                        : compositeListener);
+        final GestureDetector detector =
+                new GestureDetector(recyclerView.getContext(), compositeListener);
 
         detector.setOnDoubleTapListener(compositeListener);
 
@@ -113,9 +114,15 @@
                 new RecyclerView.OnItemTouchListener() {
                     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
                         detector.onTouchEvent(e);
-                        return false;
+
+                        // Only intercept the event if it was a mouse-based band selection.
+                        return isMouseEvent(e) && (mBandSelectManager.mIsActive ||
+                                e.getActionMasked() != MotionEvent.ACTION_UP);
                     }
-                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {}
+                    public void onTouchEvent(RecyclerView rv, MotionEvent e) {
+                        checkState(isMouseEvent(e));
+                        mBandSelectManager.processMotionEvent(e);
+                    }
                     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {}
                 });
     }
@@ -125,7 +132,7 @@
      * @hide
      */
     @VisibleForTesting
-    MultiSelectManager(Adapter<?> adapter, RecyclerViewHelper helper, int mode) {
+    MultiSelectManager(Adapter<?> adapter, MultiSelectHelper helper, int mode) {
         checkNotNull(adapter, "'adapter' cannot be null.");
         checkNotNull(helper, "'helper' cannot be null.");
 
@@ -207,6 +214,7 @@
      * @param selected
      * @return True if the selection state of the item changed.
      */
+    @VisibleForTesting
     public boolean setItemSelected(int position, boolean selected) {
         if (mSingleSelect && !mSelection.isEmpty()) {
             clearSelectionQuietly();
@@ -271,7 +279,7 @@
             if (DEBUG) Log.i(TAG, "View is null. Cannot handle tap event.");
         }
 
-        onLongPress(position);
+        onLongPress(position, e.getMetaState());
     }
 
     /**
@@ -279,17 +287,16 @@
      * can be mocked.
      *
      * @param position
+     * @param metaState as returned from {@link MotionEvent#getMetaState()}.
      * @hide
      */
     @VisibleForTesting
-    void onLongPress(int position) {
+    void onLongPress(int position, int metaState) {
         if (position == RecyclerView.NO_POSITION) {
             if (DEBUG) Log.i(TAG, "View is null. Cannot handle tap event.");
         }
 
-        if (toggleSelection(position)) {
-            notifySelectionChanged();
-        }
+        handlePositionChanged(position, metaState);
     }
 
     /**
@@ -327,17 +334,26 @@
             return false;
         }
 
+        handlePositionChanged(position, metaState);
+        return false;
+    }
+
+    /**
+     * Handles a change caused by a click on the item with the given position. If the Shift key is
+     * 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);
-        } else {
-            toggleSelection(position);
-        }
 
-        // 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();
-        return false;
+            // 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)) {
+            notifySelectionChanged();
+        }
     }
 
     /**
@@ -588,10 +604,23 @@
      */
     public static final class Selection {
 
-        private SparseBooleanArray mSelection;
+        // This class tracks selected positions by managing two arrays: the saved selection, and
+        // the total selection. Saved selections are those which have been completed by tapping an
+        // item or by completing a band select operation. Provisional selections are selections
+        // which have been temporarily created by an in-progress band select operation (once the
+        // user releases the mouse button during a band select operation, the selected items
+        // become saved). The total selection is the combination of both the saved selection and
+        // the provisional selection. Tracking both separately is necessary to ensure that saved
+        // selections do not become deselected when they are removed from the provisional selection;
+        // for example, if item A is tapped (and selected), then an in-progress band select covers A
+        // then uncovers A, A should still be selected as it has been saved. To ensure this
+        // behavior, the saved selection must be tracked separately.
+        private SparseBooleanArray mSavedSelection;
+        private SparseBooleanArray mTotalSelection;
 
         public Selection() {
-            mSelection = new SparseBooleanArray();
+            mSavedSelection = new SparseBooleanArray();
+            mTotalSelection = new SparseBooleanArray();
         }
 
         /**
@@ -599,7 +628,7 @@
          * @return true if the position is currently selected.
          */
         public boolean contains(int position) {
-            return mSelection.get(position);
+            return mTotalSelection.get(position);
         }
 
         /**
@@ -613,21 +642,85 @@
          * @return the position value stored at specified index.
          */
         public int get(int index) {
-            return mSelection.keyAt(index);
+            return mTotalSelection.keyAt(index);
         }
 
         /**
          * @return size of the selection.
          */
         public int size() {
-            return mSelection.size();
+            return mTotalSelection.size();
         }
 
         /**
          * @return true if the selection is empty.
          */
         public boolean isEmpty() {
-            return mSelection.size() == 0;
+            return mTotalSelection.size() == 0;
+        }
+
+        /**
+         * Sets the provisional selection, which is a temporary selection that can be saved,
+         * canceled, or adjusted at a later time. When a new provision selection is applied, the old
+         * one (if it exists) is abandoned.
+         * @return Array with entry for each position added or removed. Entries which were added
+         *     contain a value of true, and entries which were removed contain a value of false.
+         */
+        @VisibleForTesting
+        protected SparseBooleanArray setProvisionalSelection(
+                SparseBooleanArray provisionalSelection) {
+            SparseBooleanArray delta = new SparseBooleanArray();
+
+            for (int i = 0; i < mTotalSelection.size(); i++) {
+                int position = mTotalSelection.keyAt(i);
+                if (!provisionalSelection.get(position) && !mSavedSelection.get(position)) {
+                    // Remove each item that used to be in the selection but is unsaved and not in
+                    // the new provisional selection.
+                    delta.put(position, false);
+                }
+            }
+
+            for (int i = 0; i < provisionalSelection.size(); i++) {
+                int position = provisionalSelection.keyAt(i);
+                if (!mTotalSelection.get(position)) {
+                    // Add each item that was not previously in the selection but is in the
+                    // new provisional selection.
+                    delta.put(position, true);
+                }
+            }
+
+            // Now, iterate through the changes and actually add/remove them to/from
+            // mCurrentSelection. This could not be done in the previous loops because changing the
+            // size of the selection mid-iteration changes iteration order erroneously.
+            for (int i = 0; i < delta.size(); i++) {
+                int position = delta.keyAt(i);
+                if (delta.get(position)) {
+                    mTotalSelection.put(position, true);
+                } else {
+                    mTotalSelection.delete(position);
+                }
+            }
+
+            return delta;
+        }
+
+        /**
+         * Saves the existing provisional selection. Once the provisional selection is saved,
+         * subsequent provisional selections which are different from this existing one cannot
+         * cause items in this existing provisional selection to become deselected.
+         */
+        @VisibleForTesting
+        protected void applyProvisionalSelection() {
+            mSavedSelection = mTotalSelection.clone();
+        }
+
+        /**
+         * Abandons the existing provisional selection so that all items provisionally selected are
+         * now deselected.
+         */
+        @VisibleForTesting
+        protected void cancelProvisionalSelection() {
+            mTotalSelection = mSavedSelection.clone();
         }
 
         private boolean flip(int position) {
@@ -643,8 +736,9 @@
         /** @hide */
         @VisibleForTesting
         boolean add(int position) {
-            if (!mSelection.get(position)) {
-                mSelection.put(position, true);
+            if (!mTotalSelection.get(position)) {
+                mTotalSelection.put(position, true);
+                mSavedSelection.put(position, true);
                 return true;
             }
             return false;
@@ -653,8 +747,9 @@
         /** @hide */
         @VisibleForTesting
         boolean remove(int position) {
-            if (mSelection.get(position)) {
-                mSelection.delete(position);
+            if (mTotalSelection.get(position)) {
+                mTotalSelection.delete(position);
+                mSavedSelection.delete(position);
                 return true;
             }
             return false;
@@ -663,7 +758,8 @@
         /**
          * Adjusts the selection range to reflect the existence of newly inserted values at
          * the specified positions. This has the effect of adjusting all existing selected
-         * positions within the specified range accordingly.
+         * positions within the specified range accordingly. Note that this function discards any
+         * provisional selections which may have been applied.
          *
          * @param startPosition
          * @param count
@@ -673,11 +769,13 @@
         void expand(int startPosition, int count) {
             checkState(startPosition >= 0);
             checkState(count > 0);
+            cancelProvisionalSelection();
 
-            for (int i = 0; i < mSelection.size(); i++) {
-                int itemPosition = mSelection.keyAt(i);
+            for (int i = 0; i < mTotalSelection.size(); i++) {
+                int itemPosition = mTotalSelection.keyAt(i);
                 if (itemPosition >= startPosition) {
-                    mSelection.setKeyAt(i, itemPosition + count);
+                    mTotalSelection.setKeyAt(i, itemPosition + count);
+                    mSavedSelection.setKeyAt(i, itemPosition + count);
                 }
             }
         }
@@ -685,7 +783,8 @@
         /**
          * Adjusts the selection range to reflect the removal specified positions. This has
          * the effect of adjusting all existing selected positions within the specified range
-         * accordingly.
+         * accordingly. Note that this function discards any provisional selections which may have
+         * been applied.
          *
          * @param startPosition
          * @param count The length of the range to collapse. Must be greater than 0.
@@ -699,27 +798,30 @@
             int endPosition = startPosition + count - 1;
 
             SparseBooleanArray newSelection = new SparseBooleanArray();
-            for (int i = 0; i < mSelection.size(); i++) {
-                int itemPosition = mSelection.keyAt(i);
+            for (int i = 0; i < mSavedSelection.size(); i++) {
+                int itemPosition = mSavedSelection.keyAt(i);
                 if (itemPosition < startPosition) {
                     newSelection.append(itemPosition, true);
                 } else if (itemPosition > endPosition) {
                     newSelection.append(itemPosition - count, true);
                 }
             }
-            mSelection = newSelection;
+            mSavedSelection = newSelection;
+            cancelProvisionalSelection();
         }
 
         /** @hide */
         @VisibleForTesting
         void clear() {
-            mSelection.clear();
+            mSavedSelection.clear();
+            mTotalSelection.clear();
         }
 
         /** @hide */
         @VisibleForTesting
         void copyFrom(Selection source) {
-            mSelection = source.mSelection.clone();
+            mSavedSelection = source.mSavedSelection.clone();
+            mTotalSelection = source.mTotalSelection.clone();
         }
 
         @Override
@@ -728,16 +830,16 @@
                 return "size=0, items=[]";
             }
 
-            StringBuilder buffer = new StringBuilder(mSelection.size() * 28);
+            StringBuilder buffer = new StringBuilder(mTotalSelection.size() * 28);
             buffer.append("{size=")
-                    .append(mSelection.size())
+                    .append(mTotalSelection.size())
                     .append(", ")
                     .append("items=[");
-            for (int i=0; i < mSelection.size(); i++) {
+            for (int i=0; i < mTotalSelection.size(); i++) {
                 if (i > 0) {
                     buffer.append(", ");
                 }
-                buffer.append(mSelection.keyAt(i));
+                buffer.append(mTotalSelection.keyAt(i));
             }
             buffer.append("]}");
             return buffer.toString();
@@ -745,7 +847,7 @@
 
         @Override
         public int hashCode() {
-            return mSelection.hashCode();
+            return mSavedSelection.hashCode() ^ mTotalSelection.hashCode();
         }
 
         @Override
@@ -758,14 +860,178 @@
               return false;
           }
 
-          return mSelection.equals(((Selection) that).mSelection);
+          return mSavedSelection.equals(((Selection) that).mSavedSelection) &&
+                  mTotalSelection.equals(((Selection) that).mTotalSelection);
         }
     }
 
-    interface RecyclerViewHelper {
+    /**
+     * Provides functionality for MultiSelectManager. In practice, use RuntimeRecyclerViewHelper;
+     * this interface exists only for mocking in tests.
+     */
+    interface MultiSelectHelper {
         int findEventPosition(MotionEvent e);
     }
 
+    /**
+     * Provides functionality for BandSelectManager. In practice, use RuntimeRecyclerViewHelper;
+     * this interface exists only for mocking in tests.
+     */
+    interface BandManagerHelper {
+        void drawBand(Rect rect);
+        void addOnScrollListener(RecyclerView.OnScrollListener listener);
+        int findEventPosition(MotionEvent e);
+        int getHeight();
+        void hideBand();
+        void invalidateView();
+        void postRunnable(Runnable r);
+        void removeCallback(Runnable r);
+        void scrollBy(int dy);
+    }
+
+    /**
+     * Provides functionality for BandSelectModel. In practice, use RuntimeRecyclerViewHelper;
+     * this interface exists only for mocking in tests.
+     */
+    interface BandModelHelper {
+        void addOnScrollListener(RecyclerView.OnScrollListener listener);
+        Point createAbsolutePoint(Point relativePoint);
+        Rect getAbsoluteRectForChildViewAt(int index);
+        int getAdapterPositionAt(int index);
+        int getNumColumns();
+        int getNumRows();
+        int getTotalChildCount();
+        int getVisibleChildCount();
+        void removeOnScrollListener(RecyclerView.OnScrollListener listener);
+    }
+
+    /**
+     * Concrete RecyclerViewHelper implementation for use within the Files app.
+     */
+    private static final class RuntimeRecyclerViewHelper implements MultiSelectHelper,
+            BandManagerHelper, BandModelHelper {
+
+        private final RecyclerView mRecyclerView;
+        private final Drawable mBandSelectRect;
+
+        private boolean mIsOverlayShown = false;
+
+        RuntimeRecyclerViewHelper(RecyclerView rv) {
+            mRecyclerView = rv;
+            mBandSelectRect = mRecyclerView.getContext().getTheme().getDrawable(
+                    R.drawable.band_select_overlay);
+        }
+
+        @Override
+        public int getAdapterPositionAt(int index) {
+            View child = mRecyclerView.getChildAt(index);
+            return mRecyclerView.getChildViewHolder(child).getAdapterPosition();
+        }
+
+        @Override
+        public void addOnScrollListener(OnScrollListener listener) {
+            mRecyclerView.addOnScrollListener(listener);
+        }
+
+        @Override
+        public void removeOnScrollListener(OnScrollListener listener) {
+            mRecyclerView.removeOnScrollListener(listener);
+        }
+
+        @Override
+        public Point createAbsolutePoint(Point relativePoint) {
+            return new Point(relativePoint.x + mRecyclerView.computeHorizontalScrollOffset(),
+                    relativePoint.y + mRecyclerView.computeVerticalScrollOffset());
+        }
+
+        @Override
+        public Rect getAbsoluteRectForChildViewAt(int index) {
+            final View child = mRecyclerView.getChildAt(index);
+            final Rect childRect = new Rect();
+            child.getHitRect(childRect);
+            childRect.left += mRecyclerView.computeHorizontalScrollOffset();
+            childRect.right += mRecyclerView.computeHorizontalScrollOffset();
+            childRect.top += mRecyclerView.computeVerticalScrollOffset();
+            childRect.bottom += mRecyclerView.computeVerticalScrollOffset();
+            return childRect;
+        }
+
+        @Override
+        public int getVisibleChildCount() {
+            return mRecyclerView.getChildCount();
+        }
+
+        @Override
+        public int getTotalChildCount() {
+            return mRecyclerView.getAdapter().getItemCount();
+        }
+
+        @Override
+        public int getNumColumns() {
+            LayoutManager layoutManager = mRecyclerView.getLayoutManager();
+            if (layoutManager instanceof GridLayoutManager) {
+                return ((GridLayoutManager) layoutManager).getSpanCount();
+            }
+
+            // Otherwise, it is a list with 1 column.
+            return 1;
+        }
+
+        @Override
+        public int getNumRows() {
+            int numFullColumns = getTotalChildCount() / getNumColumns();
+            boolean hasPartiallyFullColumn = getTotalChildCount() % getNumColumns() != 0;
+            return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
+        }
+
+        @Override
+        public int findEventPosition(MotionEvent e) {
+            View view = mRecyclerView.findChildViewUnder(e.getX(), e.getY());
+            return view != null
+                    ? mRecyclerView.getChildAdapterPosition(view)
+                    : RecyclerView.NO_POSITION;
+        }
+
+        @Override
+        public int getHeight() {
+            return mRecyclerView.getHeight();
+        }
+
+        @Override
+        public void invalidateView() {
+            mRecyclerView.invalidate();
+        }
+
+        @Override
+        public void postRunnable(Runnable r) {
+            mRecyclerView.postOnAnimation(r);
+        }
+
+        @Override
+        public void removeCallback(Runnable r) {
+            mRecyclerView.removeCallbacks(r);
+        }
+
+        @Override
+        public void scrollBy(int dy) {
+            mRecyclerView.scrollBy(0, dy);
+        }
+
+        @Override
+        public void drawBand(Rect rect) {
+            mBandSelectRect.setBounds(rect);
+
+            if (!mIsOverlayShown) {
+                mRecyclerView.getOverlay().add(mBandSelectRect);
+            }
+        }
+
+        @Override
+        public void hideBand() {
+            mRecyclerView.getOverlay().remove(mBandSelectRect);
+        }
+    }
+
     public interface Callback {
         /**
          * Called when an item is selected or unselected while in selection mode.
@@ -893,4 +1159,846 @@
             return false;
         }
     }
+
+    /**
+     * Provides mouse driven band-select support when used in conjunction with {@link RecyclerView}
+     * and {@link MultiSelectManager}. This class is responsible for rendering the band select
+     * overlay and selecting overlaid items via MultiSelectManager.
+     */
+    public class BandSelectManager extends RecyclerView.OnScrollListener
+            implements BandSelectModel.OnSelectionChangedListener {
+
+        private static final int NOT_SET = -1;
+
+        private final BandManagerHelper mHelper;
+
+        private boolean mIsActive;
+        private Point mOrigin;
+        private Point mPointer;
+        private Rect mBounds;
+        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.
+        private long mScrollStartTime = NOT_SET;
+        private final Runnable mViewScroller = new ViewScroller();
+
+        public <T extends BandManagerHelper & BandModelHelper>
+                BandSelectManager(T helper) {
+            mHelper = helper;
+            mHelper.addOnScrollListener(this);
+            mModel = new BandSelectModel(helper);
+            mModel.addOnSelectionChangedListener(this);
+        }
+
+        /**
+         * Processes a MotionEvent by starting, ending, or resizing the band select overlay.
+         * @param e
+         */
+        private void processMotionEvent(MotionEvent e) {
+            if (!isMouseEvent(e)) {
+                return;
+            }
+
+            if (mIsActive && e.getActionMasked() == MotionEvent.ACTION_UP) {
+                endBandSelect();
+                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);
+            }
+
+            scrollViewIfNecessary();
+            resizeBandSelectRectangle();
+        }
+
+        /**
+         * 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);
+            mModel.startSelection(mOrigin);
+        }
+
+        /**
+         * Scrolls the view if necessary.
+         */
+        private void scrollViewIfNecessary() {
+            mHelper.removeCallback(mViewScroller);
+            mViewScroller.run();
+            mHelper.invalidateView();
+        }
+
+        /**
+         * Resizes the band select rectangle by using the origin and the current pointer position as
+         * 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));
+            mHelper.drawBand(mBounds);
+        }
+
+        /**
+         * Ends band select by removing the overlay.
+         */
+        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) {
+                setSelectionFocusBegin(firstSelected);
+            }
+        }
+
+        @Override
+        public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+            SparseBooleanArray delta = mSelection.setProvisionalSelection(updatedSelection);
+            for (int i = 0; i < delta.size(); i++) {
+                int position = delta.keyAt(i);
+                notifyItemStateChanged(position, delta.get(position));
+            }
+            notifySelectionChanged();
+        }
+
+        private class ViewScroller implements Runnable {
+            /**
+             * The number of milliseconds of scrolling at which scroll speed continues to increase.
+             * At first, the scroll starts slowly; then, the rate of scrolling increases until it
+             * reaches its maximum value at after this many milliseconds.
+             */
+            private static final long SCROLL_ACCELERATION_LIMIT_TIME_MS = 2000;
+
+            @Override
+            public void run() {
+                // Compute the number of pixels the pointer's y-coordinate is past the view.
+                // Negative values mean the pointer is at or before the top of the view, and
+                // positive values mean that the pointer is at or after the bottom of the view. Note
+                // 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 (!mIsActive || 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;
+                    return;
+                }
+
+                if (mScrollStartTime == NOT_SET) {
+                    // If the pointer was previously not at the edge of the view but now is, set the
+                    // start time for the scroll.
+                    mScrollStartTime = System.currentTimeMillis();
+                }
+
+                // Compute the number of pixels to scroll, and scroll that many pixels.
+                final int numPixels = computeScrollDistance(
+                        pixelsPastView, System.currentTimeMillis() - mScrollStartTime);
+                mHelper.scrollBy(numPixels);
+
+                mHelper.removeCallback(mViewScroller);
+                mHelper.postRunnable(this);
+            }
+
+            /**
+             * Computes the number of pixels to scroll based on how far the pointer is past the end
+             * of the view and how long it has been there. Roughly based on ItemTouchHelper's
+             * algorithm for computing the number of pixels to scroll when an item is dragged to the
+             * end of a {@link RecyclerView}.
+             * @param pixelsPastView
+             * @param scrollDuration
+             * @return
+             */
+            private int computeScrollDistance(int pixelsPastView, long scrollDuration) {
+                final int maxScrollStep = mHelper.getHeight();
+                final int direction = (int) Math.signum(pixelsPastView);
+                final int absPastView = Math.abs(pixelsPastView);
+
+                // Calculate the ratio of how far out of the view the pointer currently resides to
+                // the entire height of the view.
+                final float outOfBoundsRatio = Math.min(
+                        1.0f, (float) absPastView / mHelper.getHeight());
+                // Interpolate this ratio and use it to compute the maximum scroll that should be
+                // possible for this step.
+                final float cappedScrollStep =
+                        direction * maxScrollStep * smoothOutOfBoundsRatio(outOfBoundsRatio);
+
+                // Likewise, calculate the ratio of the time spent in the scroll to the limit.
+                final float timeRatio = Math.min(
+                        1.0f, (float) scrollDuration / SCROLL_ACCELERATION_LIMIT_TIME_MS);
+                // Interpolate this ratio and use it to compute the final number of pixels to
+                // scroll.
+                final int numPixels = (int) (cappedScrollStep * smoothTimeRatio(timeRatio));
+
+                // If the final number of pixels to scroll ends up being 0, the view should still
+                // scroll at least one pixel.
+                return numPixels != 0 ? numPixels : direction;
+            }
+
+            /**
+             * Interpolates the given out of bounds ratio on a curve which starts at (0,0) and ends
+             * at (1,1) and quickly approaches 1 near the start of that interval. This ensures that
+             * drags that are at the edge or barely past the edge of the view still cause sufficient
+             * scrolling. The equation y=(x-1)^5+1 is used, but this could also be tweaked if
+             * needed.
+             * @param ratio A ratio which is in the range [0, 1].
+             * @return A "smoothed" value, also in the range [0, 1].
+             */
+            private float smoothOutOfBoundsRatio(float ratio) {
+                return (float) Math.pow(ratio - 1.0f, 5) + 1.0f;
+            }
+
+            /**
+             * Interpolates the given time ratio on a curve which starts at (0,0) and ends at (1,1)
+             * and stays close to 0 for most input values except those very close to 1. This ensures
+             * that scrolls start out very slowly but speed up drastically after the scroll has been
+             * in progress close to SCROLL_ACCELERATION_LIMIT_TIME_MS. The equation y=x^5 is used,
+             * but this could also be tweaked if needed.
+             * @param ratio A ratio which is in the range [0, 1].
+             * @return A "smoothed" value, also in the range [0, 1].
+             */
+            private float smoothTimeRatio(float ratio) {
+                return (float) Math.pow(ratio, 5);
+            }
+        };
+
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+            if (!mIsActive) {
+                return;
+            }
+
+            // Adjust the y-coordinate of the origin the opposite number of pixels so that the
+            // origin remains in the same place relative to the view's items.
+            mOrigin.y -= dy;
+            resizeBandSelectRectangle();
+        }
+    }
+
+    /**
+     * Provides a band selection item model for views within a RecyclerView. This class queries the
+     * RecyclerView to determine where its items are placed; then, once band selection is underway,
+     * it alerts listeners of which items are covered by the selections.
+     */
+    public static final class BandSelectModel extends RecyclerView.OnScrollListener {
+
+        public static final int NOT_SET = -1;
+
+        // Enum values used to determine the corner at which the origin is located within the
+        private static final int UPPER = 0x00;
+        private static final int LOWER = 0x01;
+        private static final int LEFT = 0x00;
+        private static final int RIGHT = 0x02;
+        private static final int UPPER_LEFT = UPPER | LEFT;
+        private static final int UPPER_RIGHT = UPPER | RIGHT;
+        private static final int LOWER_LEFT = LOWER | LEFT;
+        private static final int LOWER_RIGHT = LOWER | RIGHT;
+
+        private final BandModelHelper mHelper;
+        private final List<OnSelectionChangedListener> mOnSelectionChangedListeners = new ArrayList<>();
+
+        // Map from the x-value of the left side of a SparseBooleanArray of adapter positions, keyed
+        // by their y-offset. For example, if the first column of the view starts at an x-value of 5,
+        // mColumns.get(5) would return an array of positions in that column. Within that array, the
+        // value for key y is the adapter position for the item whose y-offset is y.
+        private final SparseArray<SparseIntArray> mColumns = new SparseArray<>();
+
+        // List of limits along the x-axis. For example, if the view has two columns, this list will
+        // have two elements, each of which lists the lower- and upper-limits of the x-values of the
+        // view items. This list is sorted from furthest left to furthest right.
+        private final List<Limits> mXLimitsList = new ArrayList<>();
+
+        // Like mXLimitsList, but for y-coordinates. Note that this list only contains items which
+        // have been in the viewport. Thus, limits which exist in an area of the view to which the
+        // view has not scrolled are not present in the list.
+        private final List<Limits> mYLimitsList = new ArrayList<>();
+
+        // The adapter positions which have been recorded so far.
+        private final SparseBooleanArray mKnownPositions = new SparseBooleanArray();
+
+        // Array passed to registered OnSelectionChangedListeners. One array is created and reused
+        // throughout the lifetime of the object.
+        private final SparseBooleanArray mSelection = new SparseBooleanArray();
+
+        // The current pointer (in absolute positioning from the top of the view).
+        private Point mPointer = null;
+
+        // The bounds of the band selection.
+        private RelativePoint mRelativeOrigin;
+        private RelativePoint mRelativePointer;
+
+        private boolean mIsActive;
+
+        // Tracks where the band select originated from. This is used to determine where selections
+        // should expand from when Shift+click is used.
+        private int mPositionNearestOrigin = NOT_SET;
+
+        BandSelectModel(BandModelHelper helper) {
+            mHelper = helper;
+            mHelper.addOnScrollListener(this);
+        }
+
+        /**
+         * Stops listening to the view's scrolls. Call this function before discarding a
+         * BandSelecModel object to prevent memory leaks.
+         */
+        void stopListening() {
+            mHelper.removeOnScrollListener(this);
+        }
+
+        /**
+         * Start a band select operation at the given point.
+         * @param relativeOrigin The origin of the band select operation, relative to the viewport.
+         *     For example, if the view is scrolled to the bottom, the top-left of the viewport
+         *     would have a relative origin of (0, 0), even though its absolute point has a higher
+         *     y-value.
+         */
+        void startSelection(Point relativeOrigin) {
+            mIsActive = true;
+            mPointer = mHelper.createAbsolutePoint(relativeOrigin);
+
+            recordVisibleChildren();
+            mRelativeOrigin = new RelativePoint(mPointer);
+            mRelativePointer = new RelativePoint(mPointer);
+            computeCurrentSelection();
+            notifyListeners();
+        }
+
+        /**
+         * Resizes the selection by adjusting the pointer (i.e., the corner of the selection
+         * opposite the origin.
+         * @param relativePointer The pointer (opposite of the origin) of the band select operation,
+         *     relative to the viewport. For example, if the view is scrolled to the bottom, the
+         *     top-left of the viewport would have a relative origin of (0, 0), even though its
+         *     absolute point has a higher y-value.
+         */
+        void resizeSelection(Point relativePointer) {
+            mPointer = mHelper.createAbsolutePoint(relativePointer);
+            updateModel();
+        }
+
+        /**
+         * Ends the band selection.
+         */
+        void endSelection() {
+            mIsActive = false;
+        }
+
+        /**
+         * @return The adapter position for the item nearest the origin corresponding to the latest
+         *         band select operation, or NOT_SET if the selection did not cover any items.
+         */
+        int getPositionNearestOrigin() {
+            return mPositionNearestOrigin;
+        }
+
+        @Override
+        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
+            if (!mIsActive) {
+                return;
+            }
+
+            mPointer.x += dx;
+            mPointer.y += dy;
+            recordVisibleChildren();
+            updateModel();
+        }
+
+        /**
+         * Queries the view for all children and records their location metadata.
+         */
+        private void recordVisibleChildren() {
+            for (int i = 0; i < mHelper.getVisibleChildCount(); i++) {
+                int adapterPosition = mHelper.getAdapterPositionAt(i);
+                if (!mKnownPositions.get(adapterPosition)) {
+                    mKnownPositions.put(adapterPosition, true);
+                    recordItemData(
+                            mHelper.getAbsoluteRectForChildViewAt(i), adapterPosition);
+                }
+            }
+        }
+
+        /**
+         * Updates the limits lists and column map with the given item metadata.
+         * @param absoluteChildRect The absolute rectangle for the child view being processed.
+         * @param adapterPosition The position of the child view being processed.
+         */
+        private void recordItemData(Rect absoluteChildRect, int adapterPosition) {
+            if (mXLimitsList.size() != mHelper.getNumColumns()) {
+                // If not all x-limits have been recorded, record this one.
+                recordLimits(
+                        mXLimitsList, new Limits(absoluteChildRect.left, absoluteChildRect.right));
+            }
+
+            if (mYLimitsList.size() != mHelper.getNumRows()) {
+                // If not all y-limits have been recorded, record this one.
+                recordLimits(
+                        mYLimitsList, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
+            }
+
+            SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
+            if (columnList == null) {
+                columnList = new SparseIntArray();
+                mColumns.put(absoluteChildRect.left, columnList);
+            }
+            columnList.put(absoluteChildRect.top, adapterPosition);
+        }
+
+        /**
+         * Ensures limits exists within the sorted list limitsList, and adds it to the list if it
+         * does not exist.
+         */
+        private void recordLimits(List<Limits> limitsList, Limits limits) {
+            int index = Collections.binarySearch(limitsList, limits);
+            if (index < 0) {
+                limitsList.add(~index, limits);
+            }
+        }
+
+        /**
+         * Handles a moved pointer; this function determines whether the pointer movement resulted
+         * in a selection change and, if it has, notifies listeners of this change.
+         */
+        private void updateModel() {
+            RelativePoint old = mRelativePointer;
+            mRelativePointer = new RelativePoint(mPointer);
+            if (old != null && mRelativePointer.equals(old)) {
+                return;
+            }
+
+            computeCurrentSelection();
+            notifyListeners();
+        }
+
+        /**
+         * Computes the currently-selected items.
+         */
+        private void computeCurrentSelection() {
+            if (areItemsCoveredBySelection(mRelativePointer, mRelativeOrigin)) {
+                updateSelection(computeBounds());
+            } else {
+                mSelection.clear();
+                mPositionNearestOrigin = NOT_SET;
+            }
+        }
+
+        /**
+         * Notifies all listeners of a selection change. Note that this function simply passes
+         * mSelection, so computeCurrentSelection() should be called before this
+         * function.
+         */
+        private void notifyListeners() {
+            for (OnSelectionChangedListener listener : mOnSelectionChangedListeners) {
+                listener.onSelectionChanged(mSelection);
+            }
+        }
+
+        /**
+         * @param rect Rectangle including all covered items.
+         */
+        private void updateSelection(Rect rect) {
+            int columnStartIndex =
+                    Collections.binarySearch(mXLimitsList, new Limits(rect.left, rect.left));
+            checkState(columnStartIndex >= 0);
+            int columnEndIndex = columnStartIndex;
+
+            for (int i = columnStartIndex;
+                    i < mXLimitsList.size() && mXLimitsList.get(i).lowerLimit <= rect.right; i++) {
+                columnEndIndex = i;
+            }
+
+            SparseIntArray firstColumn =
+                    mColumns.get(mXLimitsList.get(columnStartIndex).lowerLimit);
+            int rowStartIndex = firstColumn.indexOfKey(rect.top);
+            if (rowStartIndex < 0) {
+                mPositionNearestOrigin = NOT_SET;
+                return;
+            }
+
+            int rowEndIndex = rowStartIndex;
+            for (int i = rowStartIndex;
+                    i < firstColumn.size() && firstColumn.keyAt(i) <= rect.bottom; i++) {
+                rowEndIndex = i;
+            }
+
+            updateSelection(columnStartIndex, columnEndIndex, rowStartIndex, rowEndIndex);
+        }
+
+        /**
+         * Computes the selection given the previously-computed start- and end-indices for each
+         * row and column.
+         */
+        private void updateSelection(
+                int columnStartIndex, int columnEndIndex, int rowStartIndex, int rowEndIndex) {
+            mSelection.clear();
+            for (int column = columnStartIndex; column <= columnEndIndex; column++) {
+                SparseIntArray items = mColumns.get(mXLimitsList.get(column).lowerLimit);
+                for (int row = rowStartIndex; row <= rowEndIndex; row++) {
+                    int position = items.get(items.keyAt(row));
+                    mSelection.append(position, true);
+                    if (isPossiblePositionNearestOrigin(column, columnStartIndex, columnEndIndex,
+                            row, rowStartIndex, rowEndIndex)) {
+                        // If this is the position nearest the origin, record it now so that it
+                        // can be returned by endSelection() later.
+                        mPositionNearestOrigin = position;
+                    }
+                }
+            }
+        }
+
+        /**
+         * @return Returns true if the position is the nearest to the origin, or, in the case of the
+         *     lower-right corner, whether it is possible that the position is the nearest to the
+         *     origin. See comment below for reasoning for this special case.
+         */
+        private boolean isPossiblePositionNearestOrigin(int columnIndex, int columnStartIndex,
+                int columnEndIndex, int rowIndex, int rowStartIndex, int rowEndIndex) {
+            int corner = computeCornerNearestOrigin();
+            switch (corner) {
+                case UPPER_LEFT:
+                    return columnIndex == columnStartIndex && rowIndex == rowStartIndex;
+                case UPPER_RIGHT:
+                    return columnIndex == columnEndIndex && rowIndex == rowStartIndex;
+                case LOWER_LEFT:
+                    return columnIndex == columnStartIndex && rowIndex == rowEndIndex;
+                case LOWER_RIGHT:
+                    // Note that in some cases, the last row will not have as many items as there
+                    // are columns (e.g., if there are 4 items and 3 columns, the second row will
+                    // only have one item in the first column). This function is invoked for each
+                    // position from left to right, so return true for any position in the bottom
+                    // row and only the right-most position in the bottom row will be recorded.
+                    return rowIndex == rowEndIndex;
+                default:
+                    throw new RuntimeException("Invalid corner type.");
+            }
+        }
+
+        /**
+         * Listener for changes in which items have been band selected.
+         */
+        static interface OnSelectionChangedListener {
+            public void onSelectionChanged(SparseBooleanArray updatedSelection);
+        }
+
+        void addOnSelectionChangedListener(OnSelectionChangedListener listener) {
+            mOnSelectionChangedListeners.add(listener);
+        }
+
+        void removeOnSelectionChangedListener(OnSelectionChangedListener listener) {
+            mOnSelectionChangedListeners.remove(listener);
+        }
+
+        /**
+         * Limits of a view item. For example, if an item's left side is at x-value 5 and its right side
+         * is at x-value 10, the limits would be from 5 to 10. Used to record the left- and right sides
+         * of item columns and the top- and bottom sides of item rows so that it can be determined
+         * whether the pointer is located within the bounds of an item.
+         */
+        private class Limits implements Comparable<Limits> {
+            int lowerLimit;
+            int upperLimit;
+
+            Limits(int lowerLimit, int upperLimit) {
+                this.lowerLimit = lowerLimit;
+                this.upperLimit = upperLimit;
+            }
+
+            @Override
+            public int compareTo(Limits other) {
+                return lowerLimit - other.lowerLimit;
+            }
+
+            @Override
+            public boolean equals(Object other) {
+                if (!(other instanceof Limits)) {
+                    return false;
+                }
+
+                return ((Limits) other).lowerLimit == lowerLimit &&
+                        ((Limits) other).upperLimit == upperLimit;
+            }
+        }
+
+        /**
+         * The location of a coordinate relative to items. This class represents a general area of the
+         * view as it relates to band selection rather than an explicit point. For example, two
+         * different points within an item are considered to have the same "location" because band
+         * selection originating within the item would select the same items no matter which point
+         * was used. Same goes for points between items as well as those at the very beginning or end
+         * of the view.
+         *
+         * Tracking a coordinate (e.g., an x-value) as a CoordinateLocation instead of as an int has the
+         * advantage of tying the value to the Limits of items along that axis. This allows easy
+         * selection of items within those Limits as opposed to a search through every item to see if a
+         * given coordinate value falls within those Limits.
+         */
+        private class RelativeCoordinate
+                implements Comparable<RelativeCoordinate> {
+            /**
+             * Location describing points after the last known item.
+             */
+            static final int AFTER_LAST_ITEM = 0;
+
+            /**
+             * Location describing points before the first known item.
+             */
+            static final int BEFORE_FIRST_ITEM = 1;
+
+            /**
+             * Location describing points between two items.
+             */
+            static final int BETWEEN_TWO_ITEMS = 2;
+
+            /**
+             * Location describing points within the limits of one item.
+             */
+            static final int WITHIN_LIMITS = 3;
+
+            /**
+             * The type of this coordinate, which is one of AFTER_LAST_ITEM, BEFORE_FIRST_ITEM,
+             * BETWEEN_TWO_ITEMS, or WITHIN_LIMITS.
+             */
+            final int type;
+
+            /**
+             * The limits before the coordinate; only populated when type == WITHIN_LIMITS or type ==
+             * BETWEEN_TWO_ITEMS.
+             */
+            Limits limitsBeforeCoordinate;
+
+            /**
+             * The limits after the coordinate; only populated when type == BETWEEN_TWO_ITEMS.
+             */
+            Limits limitsAfterCoordinate;
+
+            // Limits of the first known item; only populated when type == BEFORE_FIRST_ITEM.
+            Limits mFirstKnownItem;
+            // Limits of the last known item; only populated when type == AFTER_LAST_ITEM.
+            Limits mLastKnownItem;
+
+            /**
+             * @param limitsList The sorted limits list for the coordinate type. If this
+             *     CoordinateLocation is an x-value, mXLimitsList should be passed; otherwise,
+             *     mYLimitsList should be pased.
+             * @param value The coordinate value.
+             */
+            RelativeCoordinate(List<Limits> limitsList, int value) {
+                Limits dummyLimits = new Limits(value, value);
+                int index = Collections.binarySearch(limitsList, dummyLimits);
+
+                if (index >= 0) {
+                    this.type = WITHIN_LIMITS;
+                    this.limitsBeforeCoordinate = limitsList.get(index);
+                } else if (~index == 0) {
+                    this.type = BEFORE_FIRST_ITEM;
+                    this.mFirstKnownItem = limitsList.get(0);
+                } else if (~index == limitsList.size()) {
+                    Limits lastLimits = limitsList.get(limitsList.size() - 1);
+                    if (lastLimits.lowerLimit <= value && value <= lastLimits.upperLimit) {
+                        this.type = WITHIN_LIMITS;
+                        this.limitsBeforeCoordinate = lastLimits;
+                    } else {
+                        this.type = AFTER_LAST_ITEM;
+                        this.mLastKnownItem = lastLimits;
+                    }
+                } else {
+                    Limits limitsBeforeIndex = limitsList.get(~index - 1);
+                    if (limitsBeforeIndex.lowerLimit <= value && value <= limitsBeforeIndex.upperLimit) {
+                        this.type = WITHIN_LIMITS;
+                        this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+                    } else {
+                        this.type = BETWEEN_TWO_ITEMS;
+                        this.limitsBeforeCoordinate = limitsList.get(~index - 1);
+                        this.limitsAfterCoordinate = limitsList.get(~index);
+                    }
+                }
+            }
+
+            int toComparisonValue() {
+                if (type == BEFORE_FIRST_ITEM) {
+                    return mFirstKnownItem.lowerLimit - 1;
+                } else if (type == AFTER_LAST_ITEM) {
+                    return mLastKnownItem.upperLimit + 1;
+                } else if (type == BETWEEN_TWO_ITEMS) {
+                    return limitsBeforeCoordinate.upperLimit + 1;
+                } else {
+                    return limitsBeforeCoordinate.lowerLimit;
+                }
+            }
+
+            @Override
+            public boolean equals(Object other) {
+                if (!(other instanceof RelativeCoordinate)) {
+                    return false;
+                }
+
+                RelativeCoordinate otherCoordinate = (RelativeCoordinate) other;
+                return toComparisonValue() == otherCoordinate.toComparisonValue();
+            }
+
+            @Override
+            public int compareTo(RelativeCoordinate other) {
+                return toComparisonValue() - other.toComparisonValue();
+            }
+        }
+
+        /**
+         * The location of a point relative to the Limits of nearby items; consists of both an x- and
+         * y-RelativeCoordinateLocation.
+         */
+        private class RelativePoint {
+            final RelativeCoordinate xLocation;
+            final RelativeCoordinate yLocation;
+
+            RelativePoint(Point point) {
+                this.xLocation = new RelativeCoordinate(mXLimitsList, point.x);
+                this.yLocation = new RelativeCoordinate(mYLimitsList, point.y);
+            }
+
+            @Override
+            public boolean equals(Object other) {
+                if (!(other instanceof RelativePoint)) {
+                    return false;
+                }
+
+                RelativePoint otherPoint = (RelativePoint) other;
+                return xLocation.equals(otherPoint.xLocation) && yLocation.equals(otherPoint.yLocation);
+            }
+        }
+
+        /**
+         * Generates a rectangle which contains the items selected by the pointer and origin.
+         * @return The rectangle, or null if no items were selected.
+         */
+        private Rect computeBounds() {
+            Rect rect = new Rect();
+            rect.left = getCoordinateValue(
+                    min(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
+                    mXLimitsList,
+                    true);
+            rect.right = getCoordinateValue(
+                    max(mRelativeOrigin.xLocation, mRelativePointer.xLocation),
+                    mXLimitsList,
+                    false);
+            rect.top = getCoordinateValue(
+                    min(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
+                    mYLimitsList,
+                    true);
+            rect.bottom = getCoordinateValue(
+                    max(mRelativeOrigin.yLocation, mRelativePointer.yLocation),
+                    mYLimitsList,
+                    false);
+            return rect;
+        }
+
+        /**
+         * Computes the corner of the selection nearest the origin.
+         * @return
+         */
+        private int computeCornerNearestOrigin() {
+            int cornerValue = 0;
+
+            if (mRelativeOrigin.yLocation ==
+                    min(mRelativeOrigin.yLocation, mRelativePointer.yLocation)) {
+                cornerValue |= UPPER;
+            } else {
+                cornerValue |= LOWER;
+            }
+
+            if (mRelativeOrigin.xLocation ==
+                    min(mRelativeOrigin.xLocation, mRelativePointer.xLocation)) {
+                cornerValue |= LEFT;
+            } else {
+                cornerValue |= RIGHT;
+            }
+
+            return cornerValue;
+        }
+
+        private RelativeCoordinate min(RelativeCoordinate first, RelativeCoordinate second) {
+            return first.compareTo(second) < 0 ? first : second;
+        }
+
+        private RelativeCoordinate max(RelativeCoordinate first, RelativeCoordinate second) {
+            return first.compareTo(second) > 0 ? first : second;
+        }
+
+        /**
+         * @return The absolute coordinate (i.e., the x- or y-value) of the given relative
+         *     coordinate.
+         */
+        private int getCoordinateValue(RelativeCoordinate coordinate,
+                List<Limits> limitsList, boolean isStartOfRange) {
+            switch (coordinate.type) {
+                case RelativeCoordinate.BEFORE_FIRST_ITEM:
+                    return limitsList.get(0).lowerLimit;
+                case RelativeCoordinate.AFTER_LAST_ITEM:
+                    return limitsList.get(limitsList.size() - 1).upperLimit;
+                case RelativeCoordinate.BETWEEN_TWO_ITEMS:
+                    if (isStartOfRange) {
+                        return coordinate.limitsAfterCoordinate.lowerLimit;
+                    } else {
+                        return coordinate.limitsBeforeCoordinate.upperLimit;
+                    }
+                case RelativeCoordinate.WITHIN_LIMITS:
+                    return coordinate.limitsBeforeCoordinate.lowerLimit;
+            }
+
+            throw new RuntimeException("Invalid coordinate value.");
+        }
+
+        private boolean areItemsCoveredBySelection(
+                RelativePoint first, RelativePoint second) {
+            return doesCoordinateLocationCoverItems(first.xLocation, second.xLocation) &&
+                    doesCoordinateLocationCoverItems(first.yLocation, second.yLocation);
+        }
+
+        private boolean doesCoordinateLocationCoverItems(
+                RelativeCoordinate pointerCoordinate,
+                RelativeCoordinate originCoordinate) {
+            if (pointerCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM &&
+                    originCoordinate.type == RelativeCoordinate.BEFORE_FIRST_ITEM) {
+                return false;
+            }
+
+            if (pointerCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM &&
+                    originCoordinate.type == RelativeCoordinate.AFTER_LAST_ITEM) {
+                return false;
+            }
+
+            if (pointerCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+                    originCoordinate.type == RelativeCoordinate.BETWEEN_TWO_ITEMS &&
+                    pointerCoordinate.limitsBeforeCoordinate.equals(
+                            originCoordinate.limitsBeforeCoordinate) &&
+                    pointerCoordinate.limitsAfterCoordinate.equals(
+                            originCoordinate.limitsAfterCoordinate)) {
+                return false;
+            }
+
+            return true;
+        }
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
index f94aebd..b0e332f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
@@ -20,8 +20,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.Preconditions;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Maps;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -32,7 +30,7 @@
 public class ProviderExecutor extends Thread implements Executor {
 
     @GuardedBy("sExecutors")
-    private static HashMap<String, ProviderExecutor> sExecutors = Maps.newHashMap();
+    private static HashMap<String, ProviderExecutor> sExecutors = new HashMap<>();
 
     public static ProviderExecutor forAuthority(String authority) {
         synchronized (sExecutors) {
@@ -53,7 +51,7 @@
 
     private final LinkedBlockingQueue<Runnable> mQueue = new LinkedBlockingQueue<Runnable>();
 
-    private final ArrayList<WeakReference<Preemptable>> mPreemptable = Lists.newArrayList();
+    private final ArrayList<WeakReference<Preemptable>> mPreemptable = new ArrayList<>();
 
     private void preempt() {
         synchronized (mPreemptable) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 878c4c2..4685c41 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -18,7 +18,6 @@
 
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
-import android.annotation.Nullable;
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.ComponentName;
@@ -28,6 +27,7 @@
 import android.net.Uri;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.support.annotation.Nullable;
 import android.util.Log;
 
 import com.android.documentsui.BaseActivity.DocumentContext;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index f5908c5..1a7095a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,8 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
 import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.TAG;
 
 import android.app.ActivityManager;
 import android.content.AsyncTaskLoader;
@@ -36,14 +36,14 @@
 
 import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Maps;
-import com.google.common.collect.Lists;
+
 import com.google.common.util.concurrent.AbstractFuture;
 
 import libcore.io.IoUtils;
 
 import java.io.Closeable;
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -53,7 +53,7 @@
 import java.util.concurrent.TimeUnit;
 
 public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
-    private static final boolean LOGD = true;
+    private static final boolean DEBUG = false;
 
     // TODO: clean up cursor ownership so background thread doesn't traverse
     // previously returned cursors for filtering/sorting; this currently races
@@ -81,7 +81,7 @@
     private final RootsCache mRoots;
     private final State mState;
 
-    private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
+    private final HashMap<RootInfo, RecentTask> mTasks = new HashMap<>();
 
     private final int mSortOrder = State.SORT_ORDER_LAST_MODIFIED;
 
@@ -196,7 +196,7 @@
 
         // Collect all finished tasks
         boolean allDone = true;
-        List<Cursor> cursors = Lists.newArrayList();
+        List<Cursor> cursors = new ArrayList<>();
         for (RecentTask task : mTasks.values()) {
             if (task.isDone()) {
                 try {
@@ -221,7 +221,7 @@
             }
         }
 
-        if (LOGD) {
+        if (DEBUG) {
             Log.d(TAG, "Found " + cursors.size() + " of " + mTasks.size() + " recent queries done");
         }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index e11d7d9..662822e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -50,7 +50,6 @@
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
 
 import libcore.io.IoUtils;
 
@@ -157,7 +156,7 @@
         @Override
         public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
             final Collection<RootInfo> matchingRoots = mRoots.getMatchingRootsBlocking(mState);
-            final ArrayList<DocumentStack> result = Lists.newArrayList();
+            final ArrayList<DocumentStack> result = new ArrayList<>();
 
             final ContentResolver resolver = getContext().getContentResolver();
             final Cursor cursor = resolver.query(
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index fbcb938..05f7d8d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -39,14 +39,14 @@
 import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
+import android.support.annotation.VisibleForTesting;
+
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
 import libcore.io.IoUtils;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -74,10 +74,10 @@
     @GuardedBy("mLock")
     private Multimap<String, RootInfo> mRoots = ArrayListMultimap.create();
     @GuardedBy("mLock")
-    private HashSet<String> mStoppedAuthorities = Sets.newHashSet();
+    private HashSet<String> mStoppedAuthorities = new HashSet<>();
 
     @GuardedBy("mObservedAuthorities")
-    private final HashSet<String> mObservedAuthorities = Sets.newHashSet();
+    private final HashSet<String> mObservedAuthorities = new HashSet<>();
 
     public RootsCache(Context context) {
         mContext = context;
@@ -159,7 +159,7 @@
         private final String mFilterPackage;
 
         private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
-        private final HashSet<String> mTaskStoppedAuthorities = Sets.newHashSet();
+        private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
 
         /**
          * Update all roots.
@@ -251,7 +251,7 @@
             }
         }
 
-        final List<RootInfo> roots = Lists.newArrayList();
+        final List<RootInfo> roots = new ArrayList<>();
         final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
 
         ContentProviderClient client = null;
@@ -350,7 +350,7 @@
 
     @VisibleForTesting
     static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
-        final List<RootInfo> matching = Lists.newArrayList();
+        final List<RootInfo> matching = new ArrayList<>();
         for (RootInfo root : roots) {
             final boolean supportsCreate = (root.flags & Root.FLAG_SUPPORTS_CREATE) != 0;
             final boolean supportsIsChild = (root.flags & Root.FLAG_SUPPORTS_IS_CHILD) != 0;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index fd67a77..c02184b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -44,8 +44,8 @@
 import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
-import com.google.common.collect.Lists;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -293,8 +293,8 @@
             RootItem audio = null;
             RootItem downloads = null;
 
-            final List<RootInfo> clouds = Lists.newArrayList();
-            final List<RootInfo> locals = Lists.newArrayList();
+            final List<RootInfo> clouds = new ArrayList<>();
+            final List<RootInfo> locals = new ArrayList<>();
 
             for (RootInfo root : roots) {
                 if (root.isRecents()) {
@@ -338,7 +338,7 @@
                 final List<ResolveInfo> infos = pm.queryIntentActivities(
                         includeApps, PackageManager.MATCH_DEFAULT_ONLY);
 
-                final List<AppItem> apps = Lists.newArrayList();
+                final List<AppItem> apps = new ArrayList<>();
 
                 // Omit ourselves from the list
                 for (ResolveInfo info : infos) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
index 088e3fa..ae959f9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SectionedListAdapter.java
@@ -22,8 +22,6 @@
 import android.widget.BaseAdapter;
 import android.widget.ListAdapter;
 
-import com.google.android.collect.Lists;
-
 import java.util.ArrayList;
 
 /**
@@ -31,7 +29,7 @@
  * provide a header, and correctly handling item types across child adapters.
  */
 public class SectionedListAdapter extends BaseAdapter {
-    private ArrayList<SectionAdapter> mSections = Lists.newArrayList();
+    private ArrayList<SectionAdapter> mSections = new ArrayList<>();
 
     public interface SectionAdapter extends ListAdapter {
         public View getHeaderView(View convertView, ViewGroup parent);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
new file mode 100644
index 0000000..b414ee3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -0,0 +1,24 @@
+/*
+ * 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.documentsui;
+
+/**
+ * @hide
+ */
+public final class Shared {
+    public static final String TAG = "Documents";
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
index 1a5bb0c..7bb662c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/UriDerivativeLoader.java
@@ -27,16 +27,16 @@
  * changes while started, manages {@link CancellationSignal}, and caches
  * returned results.
  */
-public abstract class UriDerivativeLoader<P, R> extends AsyncTaskLoader<R> {
+public abstract class UriDerivativeLoader<Param, Res> extends AsyncTaskLoader<Res> {
     final ForceLoadContentObserver mObserver;
 
-    private final P mParam;
+    private final Param mParam;
 
-    private R mResult;
+    private Res mResult;
     private CancellationSignal mCancellationSignal;
 
     @Override
-    public final R loadInBackground() {
+    public final Res loadInBackground() {
         synchronized (this) {
             if (isLoadInBackgroundCanceled()) {
                 throw new OperationCanceledException();
@@ -52,7 +52,7 @@
         }
     }
 
-    public abstract R loadInBackground(P param, CancellationSignal signal);
+    public abstract Res loadInBackground(Param param, CancellationSignal signal);
 
     @Override
     public void cancelLoadInBackground() {
@@ -66,12 +66,12 @@
     }
 
     @Override
-    public void deliverResult(R result) {
+    public void deliverResult(Res result) {
         if (isReset()) {
             closeQuietly(result);
             return;
         }
-        R oldResult = mResult;
+        Res oldResult = mResult;
         mResult = result;
 
         if (isStarted()) {
@@ -83,7 +83,7 @@
         }
     }
 
-    public UriDerivativeLoader(Context context, P param) {
+    public UriDerivativeLoader(Context context, Param param) {
         super(context);
         mObserver = new ForceLoadContentObserver();
         mParam = param;
@@ -105,7 +105,7 @@
     }
 
     @Override
-    public void onCanceled(R result) {
+    public void onCanceled(Res result) {
         closeQuietly(result);
     }
 
@@ -122,7 +122,7 @@
         getContext().getContentResolver().unregisterContentObserver(mObserver);
     }
 
-    private void closeQuietly(R result) {
+    private void closeQuietly(Res result) {
         if (result instanceof AutoCloseable) {
             try {
                 ((AutoCloseable) result).close();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index 5d5f2eb..cc981e1e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -24,7 +24,6 @@
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
 import android.text.TextUtils;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
index 2a29cbc..e21dd49 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DurableUtils.java
@@ -16,7 +16,7 @@
 
 package com.android.documentsui.model;
 
-import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.Shared.TAG;
 
 import android.os.BadParcelableException;
 import android.os.Parcel;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java
new file mode 100644
index 0000000..20c4548
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/BandSelectModelTest.java
@@ -0,0 +1,286 @@
+/*
+ * 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.documentsui;
+
+import static org.junit.Assert.*;
+
+import com.android.documentsui.MultiSelectManager.BandSelectModel;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.util.SparseBooleanArray;
+
+import org.junit.After;
+import org.junit.Test;
+
+public class BandSelectModelTest {
+
+    private static final int VIEW_PADDING_PX = 5;
+    private static final int CHILD_VIEW_EDGE_PX = 100;
+    private static final int VIEWPORT_HEIGHT = 500;
+
+    private static BandSelectModel model;
+    private static TestHelper helper;
+    private static SparseBooleanArray lastSelection;
+    private static int viewWidth;
+
+    private static void setUp(int numChildren, int numColumns) {
+        helper = new TestHelper(numChildren, numColumns);
+        viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
+        model = new BandSelectModel(helper);
+        model.addOnSelectionChangedListener(new BandSelectModel.OnSelectionChangedListener() {
+
+            @Override
+            public void onSelectionChanged(SparseBooleanArray updatedSelection) {
+                lastSelection = updatedSelection;
+            }
+        });
+    }
+
+    @After
+    public void tearDown() {
+        model = null;
+        helper = null;
+        lastSelection = null;
+    }
+
+    @Test
+    public void testSelectionLeftOfItems() {
+        setUp(20, 5);
+        model.startSelection(new Point(0, 10));
+        model.resizeSelection(new Point(1, 11));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testSelectionRightOfItems() {
+        setUp(20, 4);
+        model.startSelection(new Point(viewWidth - 1, 10));
+        model.resizeSelection(new Point(viewWidth - 2, 11));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testSelectionAboveItems() {
+        setUp(20, 4);
+        model.startSelection(new Point(10, 0));
+        model.resizeSelection(new Point(11, 1));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testSelectionBelowItems() {
+        setUp(5, 4);
+        model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
+        model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testVerticalSelectionBetweenItems() {
+        setUp(20, 4);
+        model.startSelection(new Point(106, 0));
+        model.resizeSelection(new Point(107, 200));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testHorizontalSelectionBetweenItems() {
+        setUp(20, 4);
+        model.startSelection(new Point(0, 105));
+        model.resizeSelection(new Point(200, 106));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testGrowingAndShrinkingSelection() {
+        setUp(20, 4);
+        model.startSelection(new Point(0, 0));
+        model.resizeSelection(new Point(5, 5));
+        assertSelected(new int[] {0});
+        model.resizeSelection(new Point(109, 109));
+        assertSelected(new int[] {0});
+        model.resizeSelection(new Point(110, 109));
+        assertSelected(new int[] {0, 1});
+        model.resizeSelection(new Point(110, 110));
+        assertSelected(new int[] {0, 1, 4, 5});
+        model.resizeSelection(new Point(214, 214));
+        assertSelected(new int[] {0, 1, 4, 5});
+        model.resizeSelection(new Point(215, 214));
+        assertSelected(new int[] {0, 1, 2, 4, 5, 6});
+        model.resizeSelection(new Point(214, 214));
+        assertSelected(new int[] {0, 1, 4, 5});
+        model.resizeSelection(new Point(110, 110));
+        assertSelected(new int[] {0, 1, 4, 5});
+        model.resizeSelection(new Point(110, 109));
+        assertSelected(new int[] {0, 1});
+        model.resizeSelection(new Point(109, 109));
+        assertSelected(new int[] {0});
+        model.resizeSelection(new Point(5, 5));
+        assertSelected(new int[] {0});
+        model.resizeSelection(new Point(0, 0));
+        assertSelected(new int[0]);
+        assertEquals(BandSelectModel.NOT_SET, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testSelectionMovingAroundOrigin() {
+        setUp(16, 4);
+        model.startSelection(new Point(210, 210));
+        model.resizeSelection(new Point(viewWidth - 1, 0));
+        assertSelected(new int[] {2, 3, 6, 7});
+        model.resizeSelection(new Point(0, 0));
+        assertSelected(new int[] {0, 1, 4, 5});
+        model.resizeSelection(new Point(0, 420));
+        assertSelected(new int[] {8, 9, 12, 13});
+        model.resizeSelection(new Point(viewWidth - 1, 420));
+        assertSelected(new int[] {10, 11, 14, 15});
+        assertEquals(10, model.getPositionNearestOrigin());
+    }
+
+    @Test
+    public void testScrollingBandSelect() {
+        setUp(40, 4);
+        model.startSelection(new Point(0, 0));
+        model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+        assertSelected(new int[] {0, 4, 8, 12, 16});
+        scroll(CHILD_VIEW_EDGE_PX);
+        assertSelected(new int[] {0, 4, 8, 12, 16, 20});
+        model.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
+        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21});
+        scroll(CHILD_VIEW_EDGE_PX);
+        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25});
+        scroll(-2 * CHILD_VIEW_EDGE_PX);
+        assertSelected(new int[] {0, 1, 4, 5, 8, 9, 12, 13, 16, 17});
+        model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+        assertSelected(new int[] {0, 4, 8, 12, 16});
+        assertEquals(0, model.getPositionNearestOrigin());
+    }
+
+    private static void assertSelected(int[] selectedPositions) {
+        assertEquals(selectedPositions.length, lastSelection.size());
+        for (int position : selectedPositions) {
+            assertTrue(lastSelection.get(position));
+        }
+    }
+
+    private static void scroll(int dy) {
+        assertTrue(helper.verticalOffset + VIEWPORT_HEIGHT + dy <= helper.getTotalHeight());
+        helper.verticalOffset += dy;
+        model.onScrolled(null, 0, dy);
+    }
+
+    private static final class TestHelper implements MultiSelectManager.BandModelHelper {
+
+        public int horizontalOffset = 0;
+        public int verticalOffset = 0;
+        private final int mNumColumns;
+        private final int mNumRows;
+        private final int mNumChildren;
+
+        public TestHelper(int numChildren, int numColumns) {
+            mNumChildren = numChildren;
+            mNumColumns = numColumns;
+            mNumRows = (int) Math.ceil((double) numChildren / mNumColumns);
+        }
+
+        private int getTotalHeight() {
+            return CHILD_VIEW_EDGE_PX * mNumRows + VIEW_PADDING_PX * (mNumRows + 1);
+        }
+
+        private int getFirstVisibleRowIndex() {
+            return verticalOffset / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+        }
+
+        private int getLastVisibleRowIndex() {
+            int lastVisibleRowUncapped =
+                    (VIEWPORT_HEIGHT + verticalOffset - 1) / (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+            return Math.min(lastVisibleRowUncapped, mNumRows - 1);
+        }
+
+        private int getNumItemsInRow(int index) {
+            assertTrue(index >= 0 && index < mNumRows);
+            if (index == mNumRows - 1 && mNumChildren % mNumColumns != 0) {
+                return mNumChildren % mNumColumns;
+            }
+
+            return mNumColumns;
+        }
+
+        @Override
+        public void addOnScrollListener(OnScrollListener listener) {}
+
+        @Override
+        public void removeOnScrollListener(OnScrollListener listener) {}
+
+        @Override
+        public Point createAbsolutePoint(Point relativePoint) {
+            return new Point(
+                    relativePoint.x + horizontalOffset, relativePoint.y + verticalOffset);
+        }
+
+        @Override
+        public int getVisibleChildCount() {
+            int childCount = 0;
+            for (int i = getFirstVisibleRowIndex(); i <= getLastVisibleRowIndex(); i++) {
+                childCount += getNumItemsInRow(i);
+            }
+            return childCount;
+        }
+
+        @Override
+        public int getAdapterPositionAt(int index) {
+            return index + mNumColumns * (getFirstVisibleRowIndex());
+        }
+
+        @Override
+        public Rect getAbsoluteRectForChildViewAt(int index) {
+            int adapterPosition = getAdapterPositionAt(index);
+            int rowIndex = adapterPosition / mNumColumns;
+            int columnIndex = adapterPosition % mNumColumns;
+
+            Rect rect = new Rect();
+            rect.top = VIEW_PADDING_PX + rowIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+            rect.bottom = rect.top + CHILD_VIEW_EDGE_PX - 1;
+            rect.left = VIEW_PADDING_PX + columnIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
+            rect.right = rect.left + CHILD_VIEW_EDGE_PX - 1;
+            return rect;
+        }
+
+        @Override
+        public int getTotalChildCount() {
+            return mNumChildren;
+        }
+
+        @Override
+        public int getNumColumns() {
+            return mNumColumns;
+        }
+
+        @Override
+        public int getNumRows() {
+            return mNumRows;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
index 03ad3d4..b82251c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
@@ -19,12 +19,12 @@
 import static org.junit.Assert.*;
 
 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;
 
-import com.android.documentsui.MultiSelectManager.RecyclerViewHelper;
 import com.android.documentsui.MultiSelectManager.Selection;
 
 import org.junit.Before;
@@ -79,7 +79,7 @@
 
     @Test
     public void mouseClick_NoPosition_ClearsSelection() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         click(11);
         click(RecyclerView.NO_POSITION);
         assertSelection();
@@ -95,27 +95,27 @@
 
     @Test
     public void longPress_StartsSelectionMode() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         assertSelection(7);
     }
 
     @Test
     public void longPress_SecondPressExtendsSelection() {
-        mManager.onLongPress(7);
-        mManager.onLongPress(99);
+        mManager.onLongPress(7, 0);
+        mManager.onLongPress(99, 0);
         assertSelection(7, 99);
     }
 
     @Test
     public void singleTapUp_UnselectsSelectedItem() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         tap(7);
         assertSelection();
     }
 
     @Test
     public void singleTapUp_NoPosition_ClearsSelection() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         tap(11);
         tap(RecyclerView.NO_POSITION);
         assertSelection();
@@ -123,7 +123,7 @@
 
     @Test
     public void singleTapUp_ExtendsSelection() {
-        mManager.onLongPress(99);
+        mManager.onLongPress(99, 0);
         tap(7);
         tap(13);
         tap(129899);
@@ -132,21 +132,21 @@
 
     @Test
     public void singleTapUp_ShiftCreatesRangeSelection() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         shiftTap(17);
         assertRangeSelection(7, 17);
     }
 
     @Test
     public void singleTapUp_ShiftCreatesRangeSeletion_Backwards() {
-        mManager.onLongPress(17);
+        mManager.onLongPress(17, 0);
         shiftTap(7);
         assertRangeSelection(7, 17);
     }
 
     @Test
     public void singleTapUp_SecondShiftClickExtendsSelection() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         shiftTap(11);
         shiftTap(17);
         assertRangeSelection(7, 17);
@@ -154,7 +154,7 @@
 
     @Test
     public void singleTapUp_MultipleContiguousRangesSelected() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         shiftTap(11);
         tap(20);
         shiftTap(25);
@@ -165,7 +165,7 @@
 
     @Test
     public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         shiftTap(17);
         shiftTap(10);
         assertRangeSelection(7, 10);
@@ -173,7 +173,7 @@
 
     @Test
     public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
-        mManager.onLongPress(17);
+        mManager.onLongPress(17, 0);
         shiftTap(7);
         shiftTap(14);
         assertRangeSelection(14, 17);
@@ -182,7 +182,7 @@
 
     @Test
     public void singleTapUp_ShiftReversesSelectionDirection() {
-        mManager.onLongPress(7);
+        mManager.onLongPress(7, 0);
         shiftTap(17);
         shiftTap(0);
         assertRangeSelection(0, 7);
@@ -206,6 +206,36 @@
         assertSelection(20);
     }
 
+    @Test
+    public void provisionaSelection() {
+        Selection s = mManager.getSelection();
+        assertSelection();
+
+        SparseBooleanArray provisional = new SparseBooleanArray();
+        provisional.append(1, true);
+        provisional.append(2, true);
+        s.setProvisionalSelection(provisional);
+        assertSelection(1, 2);
+
+        provisional.delete(1);
+        provisional.append(3, true);
+        s.setProvisionalSelection(provisional);
+        assertSelection(2, 3);
+
+        s.applyProvisionalSelection();
+        assertSelection(2, 3);
+
+        provisional.clear();
+        provisional.append(3, true);
+        provisional.append(4, true);
+        s.setProvisionalSelection(provisional);
+        assertSelection(2, 3, 4);
+
+        provisional.delete(3);
+        s.setProvisionalSelection(provisional);
+        assertSelection(2, 3, 4);
+    }
+
     private void tap(int position) {
         mManager.onSingleTapUp(position, 0, MotionEvent.TOOL_TYPE_MOUSE);
     }
@@ -252,7 +282,8 @@
         assertEquals(selection.toString(), expected, selection.size());
     }
 
-    private static final class EventHelper implements RecyclerViewHelper {
+    private static final class EventHelper implements MultiSelectManager.MultiSelectHelper {
+
         @Override
         public int findEventPosition(MotionEvent e) {
             throw new UnsupportedOperationException();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 8c5bac1..1325706 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -21,7 +21,8 @@
 
 import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
-import com.google.android.collect.Lists;
+
+import com.google.common.collect.Lists;
 
 import java.util.List;
 
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
index c2f1762..6a2e03a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java
@@ -36,8 +36,6 @@
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
-import com.google.android.collect.Maps;
-
 import libcore.io.IoUtils;
 
 import java.io.File;
@@ -101,7 +99,7 @@
             });
         }
         // Create new roots.
-        mRoots = Maps.newHashMap();
+        mRoots = new HashMap<>();
         for (String rootId : rootIds) {
             final RootInfo rootInfo = new RootInfo(rootId, getSize(rootId));
             mRoots.put(rootId, rootInfo);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
index 4ffe799..d90130f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
@@ -22,6 +22,7 @@
 
 @RunWith(Suite.class)
 @SuiteClasses({
+        BandSelectModelTest.class,
         MultiSelectManager_SelectionTest.class,
         MultiSelectManagerTest.class
 })
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/KeyguardAbsKeyInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
index dfc31ab..b03871a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardAbsKeyInputView.java
@@ -40,6 +40,7 @@
     protected SecurityMessageDisplay mSecurityMessageDisplay;
     protected View mEcaView;
     protected boolean mEnableHaptics;
+    private boolean mDismissing;
 
     // To avoid accidental lockout due to events while the device in in the pocket, ignore
     // any passwords with length less than or equal to this length.
@@ -67,6 +68,7 @@
     @Override
     public void reset() {
         // start fresh
+        mDismissing = false;
         resetPasswordText(false /* animate */);
         // if the user is currently locked out, enforce it.
         long deadline = mLockPatternUtils.getLockoutAttemptDeadline(
@@ -113,6 +115,8 @@
     }
 
     protected void verifyPasswordAndUnlock() {
+        if (mDismissing) return; // already verified but haven't been dismissed; don't do it again.
+
         final String entry = getPasswordText();
         setPasswordEntryInputEnabled(false);
         if (mPendingLockCheck != null) {
@@ -143,6 +147,7 @@
 
     private void onPasswordChecked(boolean matched, int timeoutMs, boolean isValidPassword) {
         if (matched) {
+            mDismissing = true;
             mCallback.reportUnlockAttempt(true, 0);
             mCallback.dismiss(true);
         } else {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index 4cd4845..ce2d11a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -62,6 +62,7 @@
         return mPasswordEntry.requestFocus(direction, previouslyFocusedRect);
     }
 
+    @Override
     protected void resetState() {
         mPasswordEntry.setEnabled(true);
     }
@@ -69,11 +70,13 @@
     @Override
     protected void setPasswordEntryEnabled(boolean enabled) {
         mPasswordEntry.setEnabled(enabled);
+        mOkButton.setEnabled(enabled);
     }
 
     @Override
     protected void setPasswordEntryInputEnabled(boolean enabled) {
         mPasswordEntry.setEnabled(enabled);
+        mOkButton.setEnabled(enabled);
     }
 
     @Override
@@ -186,6 +189,7 @@
         mDeleteButton = findViewById(R.id.delete_button);
         mDeleteButton.setVisibility(View.VISIBLE);
         mDeleteButton.setOnClickListener(new OnClickListener() {
+            @Override
             public void onClick(View v) {
                 // check for time-based lockouts
                 if (mPasswordEntry.isEnabled()) {
@@ -195,6 +199,7 @@
             }
         });
         mDeleteButton.setOnLongClickListener(new View.OnLongClickListener() {
+            @Override
             public boolean onLongClick(View v) {
                 // check for time-based lockouts
                 if (mPasswordEntry.isEnabled()) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 77215a7..f45b9bd 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -255,7 +255,6 @@
 
         if (DEBUG) Log.d(TAG, "reportFailedPatternAttempt: #" + failedAttempts);
 
-        SecurityMode mode = mSecurityModel.getSecurityMode();
         final int currentUser = KeyguardUpdateMonitor.getCurrentUser();
         final DevicePolicyManager dpm = mLockPatternUtils.getDevicePolicyManager();
         final int failedAttemptsBeforeWipe =
@@ -264,7 +263,6 @@
         final int remainingBeforeWipe = failedAttemptsBeforeWipe > 0 ?
                 (failedAttemptsBeforeWipe - failedAttempts)
                 : Integer.MAX_VALUE; // because DPM returns 0 if no restriction
-        boolean showTimeout = false;
         if (remainingBeforeWipe < LockPatternUtils.FAILED_ATTEMPTS_BEFORE_WIPE_GRACE) {
             // The user has installed a DevicePolicyManager that requests a user/profile to be wiped
             // N attempts. Once we get below the grace period, we post this dialog every time as a
@@ -273,7 +271,8 @@
             final int expiringUser = dpm.getProfileWithMinimumFailedPasswordsForWipe(currentUser);
             int userType = USER_TYPE_PRIMARY;
             if (expiringUser == currentUser) {
-                if (expiringUser != UserHandle.USER_OWNER) {
+                // TODO: http://b/23522538
+                if (expiringUser != UserHandle.USER_SYSTEM) {
                     userType = USER_TYPE_SECONDARY_USER;
                 }
             } else if (expiringUser != UserHandle.USER_NULL) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 40dcd0d..fc6117f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -29,36 +29,19 @@
 import android.content.IntentFilter;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
-
-import static android.os.BatteryManager.BATTERY_STATUS_FULL;
-import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
-import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
-import static android.os.BatteryManager.EXTRA_STATUS;
-import static android.os.BatteryManager.EXTRA_PLUGGED;
-import static android.os.BatteryManager.EXTRA_LEVEL;
-import static android.os.BatteryManager.EXTRA_HEALTH;
-import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
-
+import android.hardware.fingerprint.FingerprintManager;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
+import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.media.AudioManager;
 import android.os.BatteryManager;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IRemoteCallback;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-
-import com.android.internal.telephony.IccCardConstants;
-import com.android.internal.telephony.IccCardConstants.State;
-import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.telephony.TelephonyIntents;
-
-import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback;
-import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
@@ -71,6 +54,12 @@
 
 import com.google.android.collect.Lists;
 
+import com.android.internal.telephony.IccCardConstants;
+import com.android.internal.telephony.IccCardConstants.State;
+import com.android.internal.telephony.PhoneConstants;
+import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.widget.LockPatternUtils;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -79,6 +68,15 @@
 import java.util.List;
 import java.util.Map.Entry;
 
+import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
+import static android.os.BatteryManager.BATTERY_STATUS_FULL;
+import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
+import static android.os.BatteryManager.EXTRA_HEALTH;
+import static android.os.BatteryManager.EXTRA_LEVEL;
+import static android.os.BatteryManager.EXTRA_MAX_CHARGING_CURRENT;
+import static android.os.BatteryManager.EXTRA_PLUGGED;
+import static android.os.BatteryManager.EXTRA_STATUS;
+
 /**
  * Watches for updates that may be interesting to the keyguard, and provides
  * the up to date information as well as a registration for callbacks that care
@@ -138,6 +136,24 @@
     private static final int MSG_SCREEN_TURNED_ON = 331;
     private static final int MSG_SCREEN_TURNED_OFF = 332;
 
+    /** Fingerprint state: Not listening to fingerprint. */
+    private static final int FINGERPRINT_STATE_STOPPED = 0;
+
+    /** Fingerprint state: Listening. */
+    private static final int FINGERPRINT_STATE_RUNNING = 1;
+
+    /**
+     * Fingerprint state: Cancelling and waiting for the confirmation from FingerprintService to
+     * send us the confirmation that cancellation has happened.
+     */
+    private static final int FINGERPRINT_STATE_CANCELLING = 2;
+
+    /**
+     * Fingerprint state: During cancelling we got another request to start listening, so when we
+     * receive the cancellation done signal, we should start listening again.
+     */
+    private static final int FINGERPRINT_STATE_CANCELLING_RESTARTING = 3;
+
     private static KeyguardUpdateMonitor sInstance;
 
     private final Context mContext;
@@ -155,7 +171,6 @@
     private boolean mFingerprintAlreadyAuthenticated;
     private boolean mBouncer;
     private boolean mBootCompleted;
-    private boolean mUserHasAuthenticatedSinceBoot;
 
     // Device provisioning state
     private boolean mDeviceProvisioned;
@@ -167,7 +182,8 @@
     private SparseIntArray mFailedAttempts = new SparseIntArray();
 
     /** Tracks whether strong authentication hasn't been used since quite some time per user. */
-    private ArraySet<Integer> mStrongAuthTimedOut = new ArraySet<>();
+    private ArraySet<Integer> mStrongAuthNotTimedOut = new ArraySet<>();
+    private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker();
 
     private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
             mCallbacks = Lists.newArrayList();
@@ -180,8 +196,8 @@
     private SubscriptionManager mSubscriptionManager;
     private AlarmManager mAlarmManager;
     private List<SubscriptionInfo> mSubscriptionInfo;
-    private boolean mFingerprintDetectionRunning;
     private TrustManager mTrustManager;
+    private int mFingerprintRunningState = FINGERPRINT_STATE_STOPPED;
 
     private final Handler mHandler = new Handler() {
         @Override
@@ -275,8 +291,6 @@
 
     private static int sCurrentUser;
 
-    private int mFpWakeMode;
-
     public synchronized static void setCurrentUser(int currentUser) {
         sCurrentUser = currentUser;
     }
@@ -429,7 +443,7 @@
             }
             onFingerprintAuthenticated(userId);
         } finally {
-            setFingerprintRunningDetectionRunning(false);
+            setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
         }
     }
 
@@ -443,7 +457,13 @@
     }
 
     private void handleFingerprintError(int msgId, String errString) {
-        setFingerprintRunningDetectionRunning(false);
+        if (msgId == FingerprintManager.FINGERPRINT_ERROR_CANCELED
+                && mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
+            setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+            startListeningForFingerprint();
+        } else {
+            setFingerprintRunningState(FINGERPRINT_STATE_STOPPED);
+        }
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -452,9 +472,15 @@
         }
     }
 
-    private void setFingerprintRunningDetectionRunning(boolean running) {
-        if (running != mFingerprintDetectionRunning) {
-            mFingerprintDetectionRunning = running;
+    private void setFingerprintRunningState(int fingerprintRunningState) {
+        boolean wasRunning = mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+        boolean isRunning = fingerprintRunningState == FINGERPRINT_STATE_RUNNING;
+        mFingerprintRunningState = fingerprintRunningState;
+
+        // Clients of KeyguardUpdateMonitor don't care about the internal state about the
+        // asynchronousness of the cancel cycle. So only notify them if the actualy running state
+        // has changed.
+        if (wasRunning != isRunning) {
             notifyFingerprintRunningStateChanged();
         }
     }
@@ -463,7 +489,7 @@
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onFingerprintRunningStateChanged(mFingerprintDetectionRunning);
+                cb.onFingerprintRunningStateChanged(isFingerprintDetectionRunning());
             }
         }
     }
@@ -482,7 +508,7 @@
     }
 
     public boolean isFingerprintDetectionRunning() {
-        return mFingerprintDetectionRunning;
+        return mFingerprintRunningState == FINGERPRINT_STATE_RUNNING;
     }
 
     private boolean isTrustDisabled(int userId) {
@@ -497,7 +523,8 @@
         final DevicePolicyManager dpm =
                 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
         return dpm != null && (dpm.getKeyguardDisabledFeatures(null, userId)
-                    & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0;
+                    & DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT) != 0
+                || isSimPinSecure();
     }
 
     public boolean getUserCanSkipBouncer(int userId) {
@@ -514,7 +541,12 @@
     }
 
     public boolean isUnlockingWithFingerprintAllowed() {
-        return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser);
+        return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
+                && !hasFingerprintUnlockTimedOut(sCurrentUser);
+    }
+
+    public StrongAuthTracker getStrongAuthTracker() {
+        return mStrongAuthTracker;
     }
 
     /**
@@ -522,11 +554,11 @@
      *         while and thus can't unlock with fingerprint, false otherwise
      */
     public boolean hasFingerprintUnlockTimedOut(int userId) {
-        return mStrongAuthTimedOut.contains(userId);
+        return !mStrongAuthNotTimedOut.contains(userId);
     }
 
     public void reportSuccessfulStrongAuthUnlockAttempt() {
-        mStrongAuthTimedOut.remove(sCurrentUser);
+        mStrongAuthNotTimedOut.add(sCurrentUser);
         scheduleStrongAuthTimeout();
         if (mFpm != null) {
             byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
@@ -541,14 +573,14 @@
         PendingIntent sender = PendingIntent.getBroadcast(mContext,
                 sCurrentUser, intent, PendingIntent.FLAG_CANCEL_CURRENT);
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, when, sender);
-        notifyStrongAuthTimedOutChanged(sCurrentUser);
+        notifyStrongAuthStateChanged(sCurrentUser);
     }
 
-    private void notifyStrongAuthTimedOutChanged(int userId) {
+    private void notifyStrongAuthStateChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onStrongAuthTimeoutExpiredChanged(userId);
+                cb.onStrongAuthStateChanged(userId);
             }
         }
     }
@@ -643,8 +675,8 @@
         public void onReceive(Context context, Intent intent) {
             if (ACTION_STRONG_AUTH_TIMEOUT.equals(intent.getAction())) {
                 int userId = intent.getIntExtra(USER_ID, -1);
-                mStrongAuthTimedOut.add(userId);
-                notifyStrongAuthTimedOutChanged(userId);
+                mStrongAuthNotTimedOut.remove(userId);
+                notifyStrongAuthStateChanged(userId);
             }
         }
     };
@@ -802,6 +834,25 @@
         }
     }
 
+    public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+        public boolean isUnlockingWithFingerprintAllowed() {
+            int userId = getCurrentUser();
+            return isFingerprintAllowedForUser(userId);
+        }
+
+        public boolean hasUserAuthenticatedSinceBoot() {
+            int userId = getCurrentUser();
+            return (getStrongAuthForUser(userId)
+                    & STRONG_AUTH_REQUIRED_AFTER_BOOT) == 0;
+        }
+
+        @Override
+        public void onStrongAuthRequiredChanged(int userId) {
+            notifyStrongAuthStateChanged(userId);
+        }
+    }
+
     public static KeyguardUpdateMonitor getInstance(Context context) {
         if (sInstance == null) {
             sInstance = new KeyguardUpdateMonitor(context);
@@ -948,6 +999,7 @@
                 PERMISSION_SELF, null /* handler */);
         mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
         mTrustManager.registerTrustListener(this);
+        new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker);
 
         mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
         updateFingerprintListeningState();
@@ -955,30 +1007,33 @@
 
     private void updateFingerprintListeningState() {
         boolean shouldListenForFingerprint = shouldListenForFingerprint();
-        if (mFingerprintDetectionRunning && !shouldListenForFingerprint) {
+        if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING && !shouldListenForFingerprint) {
             stopListeningForFingerprint();
-        } else if (!mFingerprintDetectionRunning && shouldListenForFingerprint) {
+        } else if (mFingerprintRunningState != FINGERPRINT_STATE_RUNNING
+                && shouldListenForFingerprint) {
             startListeningForFingerprint();
         }
     }
 
     private boolean shouldListenForFingerprint() {
         return (mKeyguardIsVisible || !mDeviceInteractive) && !mSwitchingUser
-                && !mFingerprintAlreadyAuthenticated;
+                && !mFingerprintAlreadyAuthenticated && !isFingerprintDisabled(getCurrentUser());
     }
 
     private void startListeningForFingerprint() {
+        if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING) {
+            setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING_RESTARTING);
+            return;
+        }
         if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
         int userId = ActivityManager.getCurrentUser();
         if (isUnlockWithFingerprintPossible(userId)) {
-            mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot(
-                    ActivityManager.getCurrentUser());
             if (mFingerprintCancelSignal != null) {
                 mFingerprintCancelSignal.cancel();
             }
             mFingerprintCancelSignal = new CancellationSignal();
             mFpm.authenticate(null, mFingerprintCancelSignal, 0, mAuthenticationCallback, null, userId);
-            setFingerprintRunningDetectionRunning(true);
+            setFingerprintRunningState(FINGERPRINT_STATE_RUNNING);
         }
     }
 
@@ -989,11 +1044,14 @@
 
     private void stopListeningForFingerprint() {
         if (DEBUG) Log.v(TAG, "stopListeningForFingerprint()");
-        if (isFingerprintDetectionRunning()) {
+        if (mFingerprintRunningState == FINGERPRINT_STATE_RUNNING) {
             mFingerprintCancelSignal.cancel();
             mFingerprintCancelSignal = null;
+            setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
         }
-        setFingerprintRunningDetectionRunning(false);
+        if (mFingerprintRunningState == FINGERPRINT_STATE_CANCELLING_RESTARTING) {
+            setFingerprintRunningState(FINGERPRINT_STATE_CANCELLING);
+        }
     }
 
     private boolean isDeviceProvisionedInSettingsDb() {
@@ -1033,6 +1091,7 @@
      * Handle {@link #MSG_DPM_STATE_CHANGED}
      */
     protected void handleDevicePolicyManagerStateChanged() {
+        updateFingerprintListeningState();
         for (int i = mCallbacks.size() - 1; i >= 0; i--) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index 7ca67b0..15ffe9f 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -233,5 +233,5 @@
      * Called when the state that the user hasn't used strong authentication since quite some time
      * has changed.
      */
-    public void onStrongAuthTimeoutExpiredChanged(int userId) { }
+    public void onStrongAuthStateChanged(int userId) { }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
index 98775b3..c1d9609 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocument.java
@@ -32,6 +32,7 @@
     private final Date mDateModified;
     private final int mSize;
     private final int mThumbSize;
+    private final boolean mReadOnly;
 
     /**
      * Constructor for root document.
@@ -40,9 +41,10 @@
         this(DUMMY_HANDLE_FOR_ROOT,
              0x3001,  // Directory.
              root.mDescription,
-             null,  // Unknown,
+             null,    // Unknown name.
              (int) Math.min(root.mMaxCapacity - root.mFreeSpace, Integer.MAX_VALUE),
-             0);
+             0,       // Total size.
+             true);   // Writable.
     }
 
     MtpDocument(MtpObjectInfo objectInfo) {
@@ -51,7 +53,8 @@
              objectInfo.getName(),
              objectInfo.getDateModified() != 0 ? new Date(objectInfo.getDateModified()) : null,
              objectInfo.getCompressedSize(),
-             objectInfo.getThumbCompressedSize());
+             objectInfo.getThumbCompressedSize(),
+             objectInfo.getProtectionStatus() != 0);
     }
 
     MtpDocument(int objectHandle,
@@ -59,30 +62,39 @@
                 String name,
                 Date dateModified,
                 int size,
-                int thumbSize) {
+                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);
+        final String mimeType = formatTypeToMimeType(mFormat);
 
         int flag = 0;
         if (mObjectHandle != DUMMY_HANDLE_FOR_ROOT) {
-            flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE;
             if (mThumbSize > 0) {
                 flag |= DocumentsContract.Document.FLAG_SUPPORTS_THUMBNAIL;
             }
+            if (!mReadOnly) {
+                flag |= DocumentsContract.Document.FLAG_SUPPORTS_DELETE |
+                        DocumentsContract.Document.FLAG_SUPPORTS_WRITE;
+            }
+        }
+        if (mimeType == DocumentsContract.Document.MIME_TYPE_DIR && !mReadOnly) {
+            flag |= DocumentsContract.Document.FLAG_DIR_SUPPORTS_CREATE;
         }
 
         builder.add(Document.COLUMN_DOCUMENT_ID, identifier.toDocumentId());
         builder.add(Document.COLUMN_DISPLAY_NAME, mName);
-        builder.add(Document.COLUMN_MIME_TYPE, getMimeType());
+        builder.add(Document.COLUMN_MIME_TYPE, mimeType); 
         builder.add(
                 Document.COLUMN_LAST_MODIFIED,
                 mDateModified != null ? mDateModified.getTime() : null);
@@ -90,9 +102,9 @@
         builder.add(Document.COLUMN_SIZE, mSize);
     }
 
-    private String getMimeType() {
+    static String formatTypeToMimeType(int format) {
         // TODO: Add complete list of mime types.
-        switch (mFormat) {
+        switch (format) {
             case 0x3001:
                 return DocumentsContract.Document.MIME_TYPE_DIR;
             case 0x3009:
@@ -100,7 +112,21 @@
             case 0x3801:
                 return "image/jpeg";
             default:
-                return "";
+                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 61b9fc5..a3cf3e2 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -96,7 +96,7 @@
             final Identifier rootIdentifier = new Identifier(root.mDeviceId, root.mStorageId);
             final MatrixCursor.RowBuilder builder = cursor.newRow();
             builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId());
-            builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD);
+            builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE);
             builder.add(Root.COLUMN_TITLE, root.mDescription);
             builder.add(
                     Root.COLUMN_DOCUMENT_ID,
@@ -167,13 +167,18 @@
     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":
+                    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());
         }
@@ -214,6 +219,24 @@
         mDocumentLoader.clearCache();
     }
 
+    @Override
+    public String createDocument(String parentDocumentId, String mimeType, String displayName)
+            throws FileNotFoundException {
+        try {
+            final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId);
+            final int objectHandle = mMtpManager.createDocument(
+                    parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType,
+                    displayName);
+            final String documentId =  new Identifier(parentId.mDeviceId, parentId.mStorageId,
+                   objectHandle).toDocumentId();
+            notifyChildDocumentsChange(parentDocumentId);
+            return documentId;
+        } catch (IOException error) {
+            Log.e(TAG, error.getMessage());
+            throw new FileNotFoundException(error.getMessage());
+        }
+    }
+
     void openDevice(int deviceId) throws IOException {
         mMtpManager.openDevice(deviceId);
         mRootScanner.scanNow();
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 3afc173..6647009 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -21,7 +21,10 @@
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
 import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
 import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract;
 import android.util.SparseArray;
 
 import java.io.FileNotFoundException;
@@ -105,6 +108,11 @@
         return results;
     }
 
+    synchronized MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        return device.getObjectInfo(objectHandle);
+    }
+
     synchronized MtpDocument getDocument(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         return new MtpDocument(device.getObjectInfo(objectHandle));
@@ -134,6 +142,27 @@
         }
     }
 
+    // TODO: Remove this method.
+    synchronized int createDocument(int deviceId, int storageId, int parentObjectHandle,
+            String mimeType, String name) throws IOException {
+        final MtpObjectInfo objectInfo = new MtpObjectInfo.Builder()
+                .setName(name)
+                .setStorageId(storageId)
+                .setParent(parentObjectHandle)
+                .setFormat(MtpDocument.mimeTypeToFormatType(mimeType))
+                .build();
+        return createDocument(deviceId, objectInfo);
+    }
+
+    synchronized int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        final MtpObjectInfo result = device.sendObjectInfo(objectInfo);
+        if (result == null) {
+            throw new IOException("Failed to create a document");
+        }
+        return result.getObjectHandle();
+    }
+
     synchronized int getParent(int deviceId, int objectHandle) throws IOException {
         final MtpDevice device = getDevice(deviceId);
         final int result = (int) device.getParent(objectHandle);
@@ -149,6 +178,13 @@
         device.importFile(objectHandle, target);
     }
 
+    synchronized void sendObject(int deviceId, int objectHandle, int size,
+            ParcelFileDescriptor source) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        if (!device.sendObject(objectHandle, size, source))
+            throw new IOException("Failed to send a document");
+    }
+
     private MtpDevice getDevice(int deviceId) throws IOException {
         final MtpDevice device = mDevices.get(deviceId);
         if (device == null) {
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/PipeManager.java
index ba13b31..53f1b65 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,70 @@
         }
     }
 
+    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.
+                final int targetObjectHandle =
+                        mManager.createDocument(
+                                mIdentifier.mDeviceId,
+                                new MtpObjectInfo.Builder(placeholderObjectInfo)
+                                        .setCompressedSize((int) tempFile.length())
+                                        .build());
+
+                // Upload the object.
+                final ParcelFileDescriptor tempInputDescriptor = ParcelFileDescriptor.open(
+                        tempFile, ParcelFileDescriptor.MODE_READ_ONLY);
+                mManager.sendObject(mIdentifier.mDeviceId,
+                        targetObjectHandle, (int) tempFile.length(), 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 5504147..1e015bd 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/DocumentLoaderTest.java
@@ -91,7 +91,8 @@
                     "file" + objectHandle,
                     new Date(),
                     1024,
-                    0 /* thumbnail size */));
+                    0 /* thumbnail size */,
+                    false /* not read only */));
         }
         manager.setObjectHandles(0, 0, MtpManager.OBJECT_HANDLE_ROOT_CHILDREN, childDocuments);
     }
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index c1da59f..1826bd0 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -140,7 +140,7 @@
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
             assertEquals("0_1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
+            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             // TODO: Add storage icon for MTP devices.
             assertTrue(cursor.isNull(2) /* icon */);
             assertEquals("Storage A", cursor.getString(3));
@@ -156,7 +156,7 @@
             cursor.moveToNext();
             cursor.moveToNext();
             assertEquals("1_1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
+            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             // TODO: Add storage icon for MTP devices.
             assertTrue(cursor.isNull(2) /* icon */);
             assertEquals("Storage B", cursor.getString(3));
@@ -194,7 +194,7 @@
             assertEquals(1, cursor.getCount());
             cursor.moveToNext();
             assertEquals("1_1", cursor.getString(0));
-            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD, cursor.getInt(1));
+            assertEquals(Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE, cursor.getInt(1));
             // TODO: Add storage icon for MTP devices.
             assertTrue(cursor.isNull(2) /* icon */);
             assertEquals("Storage B", cursor.getString(3));
@@ -210,7 +210,8 @@
                 "image.jpg" /* display name */,
                 new Date(1422716400000L) /* modified date */,
                 1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */));
+                1024 * 50 /* thumbnail size */,
+                false /* read only */));
         final Cursor cursor = mProvider.queryDocument("0_1_2", null);
         assertEquals(1, cursor.getCount());
 
@@ -221,11 +222,37 @@
         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.setDocument(0, 2, new MtpDocument(
+                2 /* object handle */,
+                0x3001 /* directory */,
+                "directory" /* display name */,
+                new Date(1422716400000L) /* modified date */,
+                0 /* file size */,
+                0 /* thumbnail size */,
+                false /* read only */));
+        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(
@@ -257,7 +284,8 @@
                 "image.jpg" /* display name */,
                 new Date(0) /* modified date */,
                 1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */));
+                1024 * 50 /* thumbnail size */,
+                true /* read only */));
 
         final Cursor cursor = mProvider.queryChildDocuments("0_0_0", null, null);
         assertEquals(1, cursor.getCount());
@@ -267,10 +295,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());
@@ -302,7 +327,8 @@
                 "image.jpg" /* display name */,
                 new Date(1422716400000L) /* modified date */,
                 1024 * 1024 * 5 /* file size */,
-                1024 * 50 /* thumbnail size */));
+                1024 * 50 /* thumbnail size */,
+                false /* not read only */));
         mMtpManager.setParent(0, 1, 2);
         mProvider.deleteDocument("0_0_1");
         assertEquals(1, mResolver.getChangeCount(
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..cfb8b04 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/PipeManagerTest.java
@@ -21,6 +21,7 @@
 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 +31,80 @@
     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.setDocument(0, 1, new MtpDocument(1, 0, "", new Date(), 0, 0, false));
+
+        // 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 MtpDocument placeholderDocument = mtpManager.getDocument(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 MtpDocument targetDocument = mtpManager.getDocument(
+                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 +117,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..94b5ba0 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);
     }
@@ -65,6 +70,10 @@
         mImportFileBytes.put(pack(deviceId, objectHandle), bytes);
     }
 
+    byte[] getImportFileBytes(int deviceId, int objectHandle) {
+        return mImportFileBytes.get(pack(deviceId, objectHandle));
+    }
+
     void setThumbnail(int deviceId, int objectHandle, byte[] bytes) {
         mThumbnailBytes.put(pack(deviceId, objectHandle), bytes);
     }
@@ -109,6 +118,15 @@
     }
 
     @Override
+    MtpObjectInfo getObjectInfo(int deviceId, int objectHandle) throws IOException {
+        final MtpDocument document = getDocument(deviceId, objectHandle);
+        // It's impossible to set an object id of MtpObjectInfo at this stage. Also,
+        // it's hard to get any information from MtpDocument, as it's designed to return them
+        // only via cursors. Rework these.
+        return new MtpObjectInfo.Builder().build();
+    }
+
+    @Override
     int[] getObjectHandles(int deviceId, int storageId, int parentObjectHandle) throws IOException {
         final String key = pack(deviceId, storageId, parentObjectHandle);
         if (mObjectHandles.containsKey(key)) {
@@ -119,8 +137,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 +151,44 @@
     }
 
     @Override
+    int createDocument(int deviceId, MtpObjectInfo objectInfo) throws IOException {
+        // For simplicity, it allows to create only one document, and it always has the hardcoded
+        // CREATED_DOCUMENT_HANDLE document handle.
+        final String key = pack(deviceId, CREATED_DOCUMENT_HANDLE);
+        if (!mDocuments.containsKey(key)) {
+            mDocuments.put(key, new MtpDocument(
+                  CREATED_DOCUMENT_HANDLE,
+                  objectInfo.getFormat(),
+                  objectInfo.getName(),
+                  new Date(objectInfo.getDateModified()),
+                  objectInfo.getCompressedSize(),
+                  objectInfo.getThumbCompressedSize(),
+                  false /* Always writable for testing. */));
+        } else {
+            throw new IOException();
+        }
+        return CREATED_DOCUMENT_HANDLE;
+    }
+
+    @Override
+    void sendObject(int deviceId, int objectHandle, int size, ParcelFileDescriptor source)
+            throws IOException {
+        final String key = pack(deviceId, objectHandle);
+        if (!mDocuments.containsKey(key)) {
+            throw new IOException();
+        }
+
+        ParcelFileDescriptor.AutoCloseInputStream inputStream =
+                new ParcelFileDescriptor.AutoCloseInputStream(source);
+        byte[] buffer = new byte[size];
+        if (inputStream.read(buffer, 0, size) != size) {
+            throw new IOException();
+        }
+
+        mImportFileBytes.put(pack(deviceId, objectHandle), buffer);
+    }
+
+    @Override
     byte[] getThumbnail(int deviceId, int objectHandle) throws IOException {
         final String key = pack(deviceId, objectHandle);
         if (mThumbnailBytes.containsKey(key)) {
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/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index 1c4b05f..3ad8f21 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -21,4 +21,6 @@
 
     <!-- The translation for disappearing security views after having solved them. -->
     <dimen name="disappear_y_translation">-32dp</dimen>
-</resources>
\ No newline at end of file
+
+    <dimen name="circle_avatar_size">40dp</dimen>
+</resources>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b03f100..9b1f103 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -195,4 +195,34 @@
     <!-- Content description of the WIFI signal when it is full for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_wifi_signal_full">Wifi signal full.</string>
 
+    <!-- Label for kernel threads in battery usage -->
+    <string name="process_kernel_label">Android OS</string>
+    <!-- Title of data usage item that represents all uninstalled applications. [CHAR LIMIT=48] -->
+    <string name="data_usage_uninstalled_apps">Removed apps</string>
+    <!-- Title of data usage item that represents all uninstalled applications or removed users. [CHAR LIMIT=48] -->
+    <string name="data_usage_uninstalled_apps_users">Removed apps and users</string>
+
+    <!-- Tethering controls, item title to go into the tethering settings -->
+    <!-- Tethering controls, item title to go into the tethering settings when only USB tethering is available [CHAR LIMIT=25]-->
+    <string name="tether_settings_title_usb">USB tethering</string>
+    <!-- Tethering controls, item title to go into the tethering settings when only Wifi tethering is available [CHAR LIMIT=25]-->
+    <string name="tether_settings_title_wifi">Portable hotspot</string>
+    <!-- Tethering controls, item title to go into the tethering settings when only Bluetooth tethering is available [CHAR LIMIT=25]-->
+    <string name="tether_settings_title_bluetooth">Bluetooth tethering</string>
+    <!-- Tethering controls, item title to go into the tethering settings when USB and Bluetooth tethering are available [CHAR LIMIT=25]-->
+    <string name="tether_settings_title_usb_bluetooth">Tethering</string>
+    <!-- Tethering controls, item title to go into the tethering settings when USB, Bluetooth and Wifi tethering are available [CHAR LIMIT=25]-->
+    <string name="tether_settings_title_all">Tethering &amp; portable hotspot</string>
+
+    <!-- Title for a work profile. [CHAR LIMIT=25] -->
+    <string name="managed_user_title">Work profile</string>
+
+    <!-- Title for Guest user [CHAR LIMIT=35] -->
+    <string name="user_guest">Guest</string>
+
+    <!-- Manage apps, individual app screen, substituted for the application's label when the app's label CAN NOT be determined.-->
+    <string name="unknown">Unknown</string>
+
+    <!-- [CHAR LIMIT=NONE] Label of a running process that represents another user -->
+    <string name="running_process_item_user_label">User: <xliff:g id="user_name">%1$s</xliff:g></string>
 </resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 096a5c4..f52d755 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -54,29 +54,7 @@
     public static boolean setWifiTethering(boolean enable, Context context) {
         final WifiManager wifiManager =
                 (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
-        final ContentResolver cr = context.getContentResolver();
-        /**
-         * Disable Wifi if enabling tethering
-         */
-        int wifiState = wifiManager.getWifiState();
-        if (enable && ((wifiState == WifiManager.WIFI_STATE_ENABLING) ||
-                    (wifiState == WifiManager.WIFI_STATE_ENABLED))) {
-            wifiManager.setWifiEnabled(false);
-            Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 1);
-        }
-
-        boolean success = wifiManager.setWifiApEnabled(null, enable);
-        /**
-         *  If needed, restore Wifi on tether disable
-         */
-        if (!enable) {
-            int wifiSavedState = Settings.Global.getInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-            if (wifiSavedState == 1) {
-                wifiManager.setWifiEnabled(true);
-                Settings.Global.putInt(cr, Settings.Global.WIFI_SAVED_STATE, 0);
-            }
-        }
-        return success;
+        return wifiManager.setWifiApEnabled(null, enable);
     }
 
     public static boolean isWifiTetherEnabled(Context context) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
new file mode 100644
index 0000000..621a09cd
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -0,0 +1,84 @@
+package com.android.settingslib;
+
+import android.content.Context;
+import android.content.pm.UserInfo;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.os.UserManager;
+
+import com.android.internal.util.UserIcons;
+import com.android.settingslib.drawable.CircleFramedDrawable;
+
+public final class Utils {
+
+    /**
+     * Return string resource that best describes combination of tethering
+     * options available on this device.
+     */
+    public static int getTetheringLabel(ConnectivityManager cm) {
+        String[] usbRegexs = cm.getTetherableUsbRegexs();
+        String[] wifiRegexs = cm.getTetherableWifiRegexs();
+        String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
+
+        boolean usbAvailable = usbRegexs.length != 0;
+        boolean wifiAvailable = wifiRegexs.length != 0;
+        boolean bluetoothAvailable = bluetoothRegexs.length != 0;
+
+        if (wifiAvailable && usbAvailable && bluetoothAvailable) {
+            return R.string.tether_settings_title_all;
+        } else if (wifiAvailable && usbAvailable) {
+            return R.string.tether_settings_title_all;
+        } else if (wifiAvailable && bluetoothAvailable) {
+            return R.string.tether_settings_title_all;
+        } else if (wifiAvailable) {
+            return R.string.tether_settings_title_wifi;
+        } else if (usbAvailable && bluetoothAvailable) {
+            return R.string.tether_settings_title_usb_bluetooth;
+        } else if (usbAvailable) {
+            return R.string.tether_settings_title_usb;
+        } else {
+            return R.string.tether_settings_title_bluetooth;
+        }
+    }
+
+    /**
+     * Returns a label for the user, in the form of "User: user name" or "Work profile".
+     */
+    public static String getUserLabel(Context context, UserInfo info) {
+        String name = info != null ? info.name : null;
+        if (info.isManagedProfile()) {
+            // We use predefined values for managed profiles
+            return context.getString(R.string.managed_user_title);
+        } else if (info.isGuest()) {
+            name = context.getString(R.string.user_guest);
+        }
+        if (name == null && info != null) {
+            name = Integer.toString(info.id);
+        } else if (info == null) {
+            name = context.getString(R.string.unknown);
+        }
+        return context.getResources().getString(R.string.running_process_item_user_label, name);
+    }
+
+    /**
+     * Returns a circular icon for a user.
+     */
+    public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
+        if (user.isManagedProfile()) {
+            // We use predefined values for managed profiles
+            Bitmap b = BitmapFactory.decodeResource(context.getResources(),
+                    com.android.internal.R.drawable.ic_corp_icon);
+            return CircleFramedDrawable.getInstance(context, b);
+        }
+        if (user.iconPath != null) {
+            Bitmap icon = um.getUserIcon(user.id);
+            if (icon != null) {
+                return CircleFramedDrawable.getInstance(context, icon);
+            }
+        }
+        return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(
+                UserIcons.getDefaultUserIcon(user.id, /* light= */ false)));
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
new file mode 100644
index 0000000..278b57d
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/drawable/CircleFramedDrawable.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.drawable;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.drawable.Drawable;
+
+import com.android.settingslib.R;
+
+/**
+ * Converts the user avatar icon to a circularly clipped one.
+ * TODO: Move this to an internal framework class and share with the one in Keyguard.
+ */
+public class CircleFramedDrawable extends Drawable {
+
+    private final Bitmap mBitmap;
+    private final int mSize;
+    private final Paint mPaint;
+
+    private float mScale;
+    private Rect mSrcRect;
+    private RectF mDstRect;
+
+    public static CircleFramedDrawable getInstance(Context context, Bitmap icon) {
+        Resources res = context.getResources();
+        float iconSize = res.getDimension(R.dimen.circle_avatar_size);
+
+        CircleFramedDrawable instance = new CircleFramedDrawable(icon, (int) iconSize);
+        return instance;
+    }
+
+    public CircleFramedDrawable(Bitmap icon, int size) {
+        super();
+        mSize = size;
+
+        mBitmap = Bitmap.createBitmap(mSize, mSize, Bitmap.Config.ARGB_8888);
+        final Canvas canvas = new Canvas(mBitmap);
+
+        final int width = icon.getWidth();
+        final int height = icon.getHeight();
+        final int square = Math.min(width, height);
+
+        final Rect cropRect = new Rect((width - square) / 2, (height - square) / 2, square, square);
+        final RectF circleRect = new RectF(0f, 0f, mSize, mSize);
+
+        final Path fillPath = new Path();
+        fillPath.addArc(circleRect, 0f, 360f);
+
+        canvas.drawColor(0, PorterDuff.Mode.CLEAR);
+
+        // opaque circle matte
+        mPaint = new Paint();
+        mPaint.setAntiAlias(true);
+        mPaint.setColor(Color.BLACK);
+        mPaint.setStyle(Paint.Style.FILL);
+        canvas.drawPath(fillPath, mPaint);
+
+        // mask in the icon where the bitmap is opaque
+        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
+        canvas.drawBitmap(icon, cropRect, circleRect, mPaint);
+
+        // prepare paint for frame drawing
+        mPaint.setXfermode(null);
+
+        mScale = 1f;
+
+        mSrcRect = new Rect(0, 0, mSize, mSize);
+        mDstRect = new RectF(0, 0, mSize, mSize);
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        final float inside = mScale * mSize;
+        final float pad = (mSize - inside) / 2f;
+
+        mDstRect.set(pad, pad, mSize - pad, mSize - pad);
+        canvas.drawBitmap(mBitmap, mSrcRect, mDstRect, null);
+    }
+
+    public void setScale(float scale) {
+        mScale = scale;
+    }
+
+    public float getScale() {
+        return mScale;
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter cf) {
+    }
+    
+    @Override
+    public int getIntrinsicWidth() {
+        return mSize;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mSize;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
new file mode 100644
index 0000000..572bae1
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/SummaryForAllUidLoader.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import android.content.AsyncTaskLoader;
+import android.content.Context;
+import android.net.INetworkStatsSession;
+import android.net.NetworkStats;
+import android.net.NetworkTemplate;
+import android.os.Bundle;
+import android.os.RemoteException;
+
+public class SummaryForAllUidLoader extends AsyncTaskLoader<NetworkStats> {
+    private static final String KEY_TEMPLATE = "template";
+    private static final String KEY_START = "start";
+    private static final String KEY_END = "end";
+
+    private final INetworkStatsSession mSession;
+    private final Bundle mArgs;
+
+    public static Bundle buildArgs(NetworkTemplate template, long start, long end) {
+        final Bundle args = new Bundle();
+        args.putParcelable(KEY_TEMPLATE, template);
+        args.putLong(KEY_START, start);
+        args.putLong(KEY_END, end);
+        return args;
+    }
+
+    public SummaryForAllUidLoader(Context context, INetworkStatsSession session, Bundle args) {
+        super(context);
+        mSession = session;
+        mArgs = args;
+    }
+
+    @Override
+    protected void onStartLoading() {
+        super.onStartLoading();
+        forceLoad();
+    }
+
+    @Override
+    public NetworkStats loadInBackground() {
+        final NetworkTemplate template = mArgs.getParcelable(KEY_TEMPLATE);
+        final long start = mArgs.getLong(KEY_START);
+        final long end = mArgs.getLong(KEY_END);
+
+        try {
+            return mSession.getSummaryForAllUid(template, start, end, false);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    @Override
+    protected void onStopLoading() {
+        super.onStopLoading();
+        cancelLoad();
+    }
+
+    @Override
+    protected void onReset() {
+        super.onReset();
+        cancelLoad();
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java
new file mode 100644
index 0000000..5e42281
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetail.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import android.graphics.drawable.Drawable;
+
+public class UidDetail {
+    public CharSequence label;
+    public CharSequence contentDescription;
+    public CharSequence[] detailLabels;
+    public CharSequence[] detailContentDescriptions;
+    public Drawable icon;
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
new file mode 100644
index 0000000..224b967
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.net;
+
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.UserInfo;
+import android.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.net.ConnectivityManager;
+import android.net.TrafficStats;
+import android.os.UserManager;
+import android.os.UserHandle;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.settingslib.R;
+import com.android.settingslib.Utils;
+
+/**
+ * Return details about a specific UID, handling special cases like
+ * {@link TrafficStats#UID_TETHERING} and {@link UserInfo}.
+ */
+public class UidDetailProvider {
+    private static final String TAG = "DataUsage";
+    private final Context mContext;
+    private final SparseArray<UidDetail> mUidDetailCache;
+
+    public static final int OTHER_USER_RANGE_START = -2000;
+
+    public static int buildKeyForUser(int userHandle) {
+        return OTHER_USER_RANGE_START - userHandle;
+    }
+
+    public static boolean isKeyForUser(int key) {
+        return key <= OTHER_USER_RANGE_START;
+    }
+
+    public static int getUserIdForKey(int key) {
+        return OTHER_USER_RANGE_START - key;
+    }
+
+    public UidDetailProvider(Context context) {
+        mContext = context.getApplicationContext();
+        mUidDetailCache = new SparseArray<UidDetail>();
+    }
+
+    public void clearCache() {
+        synchronized (mUidDetailCache) {
+            mUidDetailCache.clear();
+        }
+    }
+
+    /**
+     * Resolve best descriptive label for the given UID.
+     */
+    public UidDetail getUidDetail(int uid, boolean blocking) {
+        UidDetail detail;
+
+        synchronized (mUidDetailCache) {
+            detail = mUidDetailCache.get(uid);
+        }
+
+        if (detail != null) {
+            return detail;
+        } else if (!blocking) {
+            return null;
+        }
+
+        detail = buildUidDetail(uid);
+
+        synchronized (mUidDetailCache) {
+            mUidDetailCache.put(uid, detail);
+        }
+
+        return detail;
+    }
+
+    /**
+     * Build {@link UidDetail} object, blocking until all {@link Drawable}
+     * lookup is finished.
+     */
+    private UidDetail buildUidDetail(int uid) {
+        final Resources res = mContext.getResources();
+        final PackageManager pm = mContext.getPackageManager();
+
+        final UidDetail detail = new UidDetail();
+        detail.label = pm.getNameForUid(uid);
+        detail.icon = pm.getDefaultActivityIcon();
+
+        // handle special case labels
+        switch (uid) {
+            case android.os.Process.SYSTEM_UID:
+                detail.label = res.getString(R.string.process_kernel_label);
+                detail.icon = pm.getDefaultActivityIcon();
+                return detail;
+            case TrafficStats.UID_REMOVED:
+                detail.label = res.getString(UserManager.supportsMultipleUsers()
+                        ? R.string.data_usage_uninstalled_apps_users
+                        : R.string.data_usage_uninstalled_apps);
+                detail.icon = pm.getDefaultActivityIcon();
+                return detail;
+            case TrafficStats.UID_TETHERING:
+                final ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
+                        Context.CONNECTIVITY_SERVICE);
+                detail.label = res.getString(Utils.getTetheringLabel(cm));
+                detail.icon = pm.getDefaultActivityIcon();
+                return detail;
+        }
+
+        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+
+        // Handle keys that are actually user handles
+        if (isKeyForUser(uid)) {
+            final int userHandle = getUserIdForKey(uid);
+            final UserInfo info = um.getUserInfo(userHandle);
+            if (info != null) {
+                detail.label = Utils.getUserLabel(mContext, info);
+                detail.icon = Utils.getUserIcon(mContext, um, info);
+                return detail;
+            }
+        }
+
+        // otherwise fall back to using packagemanager labels
+        final String[] packageNames = pm.getPackagesForUid(uid);
+        final int length = packageNames != null ? packageNames.length : 0;
+        try {
+            final int userId = UserHandle.getUserId(uid);
+            UserHandle userHandle = new UserHandle(userId);
+            IPackageManager ipm = AppGlobals.getPackageManager();
+            if (length == 1) {
+                final ApplicationInfo info = ipm.getApplicationInfo(packageNames[0],
+                        0 /* no flags */, userId);
+                if (info != null) {
+                    detail.label = info.loadLabel(pm).toString();
+                    detail.icon = um.getBadgedIconForUser(info.loadIcon(pm),
+                            new UserHandle(userId));
+                }
+            } else if (length > 1) {
+                detail.detailLabels = new CharSequence[length];
+                detail.detailContentDescriptions = new CharSequence[length];
+                for (int i = 0; i < length; i++) {
+                    final String packageName = packageNames[i];
+                    final PackageInfo packageInfo = pm.getPackageInfo(packageName, 0);
+                    final ApplicationInfo appInfo = ipm.getApplicationInfo(packageName,
+                            0 /* no flags */, userId);
+
+                    if (appInfo != null) {
+                        detail.detailLabels[i] = appInfo.loadLabel(pm).toString();
+                        detail.detailContentDescriptions[i] = um.getBadgedLabelForUser(
+                                detail.detailLabels[i], userHandle);
+                        if (packageInfo.sharedUserLabel != 0) {
+                            detail.label = pm.getText(packageName, packageInfo.sharedUserLabel,
+                                    packageInfo.applicationInfo).toString();
+                            detail.icon = um.getBadgedIconForUser(appInfo.loadIcon(pm), userHandle);
+                        }
+                    }
+                }
+            }
+            detail.contentDescription = um.getBadgedLabelForUser(detail.label, userHandle);
+        } catch (NameNotFoundException e) {
+            Log.w(TAG, "Error while building UI detail for uid "+uid, e);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Error while building UI detail for uid "+uid, e);
+        }
+
+        if (TextUtils.isEmpty(detail.label)) {
+            detail.label = Integer.toString(uid);
+        }
+
+        return detail;
+    }
+}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 345f682..e00b55e 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -65,6 +65,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" />
@@ -104,6 +105,7 @@
     <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
     <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
     <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
+    <uses-permission android:name="android.permission.GET_APP_OPS_STATS" />
 
     <application android:label="@string/app_label">
         <provider
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index 51fea2a..314b3c4 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -3,13 +3,15 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-proto-files-under,src) \
     src/com/android/systemui/EventLogTags.logtags
 
 LOCAL_STATIC_JAVA_LIBRARIES := Keyguard
 LOCAL_JAVA_LIBRARIES := telephony-common
 
 LOCAL_PACKAGE_NAME := SystemUI
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
 LOCAL_CERTIFICATE := platform
 LOCAL_PRIVILEGED_MODULE := true
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 8ab53b8..e4fc075 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -168,14 +168,14 @@
                 android:permission="android.permission.BIND_WALLPAPER"
                 android:exported="true" />
 
-        <receiver android:name=".BootReceiver" androidprv:primaryUserOnly="true">
+        <receiver android:name=".BootReceiver" androidprv:systemUserOnly="true">
             <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
 
         <receiver android:name=".qs.tiles.HotspotTile$APChangedReceiver"
-                androidprv:primaryUserOnly="true">
+                androidprv:systemUserOnly="true">
             <intent-filter>
                 <action android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
             </intent-filter>
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/navbar_fade_in.xml b/packages/SystemUI/res/anim/navbar_fade_in.xml
index e3429e6..7051730 100644
--- a/packages/SystemUI/res/anim/navbar_fade_in.xml
+++ b/packages/SystemUI/res/anim/navbar_fade_in.xml
@@ -19,4 +19,5 @@
     android:fromAlpha="0.0"
     android:toAlpha="1.0"
     android:interpolator="@android:interpolator/linear_out_slow_in"
+    android:startDelay="32"
     android:duration="200"/>
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/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/interpolator/error_to_trustedstate_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
new file mode 100755
index 0000000..262cb88
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/error_to_trustedstate_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
new file mode 100755
index 0000000..9ecee94
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/error_to_trustedstate_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
new file mode 100755
index 0000000..ae0b2d7
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/error_to_trustedstate_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
new file mode 100755
index 0000000..be7cc69
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/error_to_trustedstate_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
new file mode 100755
index 0000000..f8f978d
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/error_to_trustedstate_animation_interpolator_4.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/trusted_state_to_error_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
new file mode 100755
index 0000000..9ecee94
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_0.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/trusted_state_to_error_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
new file mode 100755
index 0000000..87ef1d4
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_1.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/trusted_state_to_error_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
new file mode 100755
index 0000000..be7cc69
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_2.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/interpolator/trusted_state_to_error_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
new file mode 100755
index 0000000..83af65a
--- /dev/null
+++ b/packages/SystemUI/res/interpolator/trusted_state_to_error_animation_interpolator_3.xml
@@ -0,0 +1,19 @@
+<?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.
+-->
+<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/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 26d5274..9294a16 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Verwyder uit Instellings"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Verwyder Stelsel-UI-ontvanger uit Instellings en staak die gebruik van al sy kenmerke?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index e61b6c3..13f768d 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ከቅንብሮች አስወግድ"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ከቅንብሮች ላይ የስርዓት በይነገጽ መቃኛ ተወግዶ ሁሉም ባህሪዎቹን መጠቀም ይቁም?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"መተግበሪያ በእርስዎ መሣሪያ ላይ አልተጫነም"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"የሰዓት ሰከንዶችን አሳይ"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"የሰዓት ሰከንዶችን በሁኔታ አሞሌ ውስጥ አሳይ። በባትሪ ዕድሜ ላይ ተጽዕኖ ሊኖርው ይችል ይሆናል።"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 2e358a1..6889a43 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -437,4 +437,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"إزالة من الإعدادات"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"هل تريد إزالة أداة ضبط واجهة مستخدم النظام من الإعدادات وإيقاف استخدام كل ميزاتها؟"</string>
     <string name="activity_not_found" msgid="348423244327799974">"التطبيق غير مثبّت على جهازك"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"عرض ثواني الساعة"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"عرض ثواني الساعة في شريط الحالة. قد يؤثر ذلك في عمر البطارية."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index b82b42e..51513bd 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Ayarlardan Silin"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Ayarlardan silinsin və onun bütün funksiyalarından istifadə dayandırılsın?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 82ace52..014d802 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Премахване от „Настройки“"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Да се премахне ли от „Настройки“ тунерът на системния потребителски интерфейс и да се спре ли използването на всичките му функции?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Приложението не е инсталирано на устройството ви"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Показване на секундите на часовника"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Показване на секундите на часовника в лентата на състоянието. Може да се отрази на живота на батерията."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 884fc42..0860019 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"সেটিংস থেকে সরান"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"সেটিংস থেকে সিস্টেম UI টিউনার সরাতে এবং এটির সমস্ত বৈশিষ্ট্য ব্যবহার করা বন্ধ করতে চান?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"আপনার ডিভাইসে অ্যাপ্লিকেশান ইনস্টল করা নেই"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ঘড়ির সেকেন্ড দেখায়"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"স্থিতি দন্ডে ঘড়ির সেকেন্ড দেখায়৷ ব্যাটারি লাইফকে প্রভাবিত করতে পারে৷"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cc04fd6..9c32052 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>
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Treu de Configuració"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols treure el Configurador de la UI del sistema de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 7f94577..4d96a01 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -437,4 +437,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Odstranit z Nastavení"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Chcete nástroj na ladění uživatelského rozhraní systému odstranit z Nastavení a přestat používat všechny jeho funkce?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 2129f03..7f005a3 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Fjern fra Indstillinger"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vil du fjerne System UI Tuner fra Indstillinger og stoppe med at bruge alle dens funktioner?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 30a2baf..36f3c98 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Aus \"Einstellungen\" entfernen"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner aus \"Einstellungen\" entfernen und die Verwendung von allen zugehörigen Funktionen beenden?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index f2fc602..8e73b21 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Κατάργηση από τις Ρυθμίσεις"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Κατάργηση System UI Tuner από τις Ρυθμίσεις και διακοπή χρήσης όλων των λειτουργιών του;"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Η εφαρμογή δεν έχει εγκατασταθεί στη συσκευή σας"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Εμφάνιση δευτερολέπτων ρολογιού"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Εμφάνιση δευτερολέπτων ρολογιού στη γραμμή κατάστασης. Ενδέχεται να επηρεάσει τη διάρκεια ζωής της μπαταρίας."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index f1aafb6..0b49955 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index f1aafb6..0b49955 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index f1aafb6..0b49955 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remove from settings"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remove System UI Tuner from Settings and stop using all of its features?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 5136545..c4dca9c 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Quitar de Configuración"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Quieres quitar el sintonizador de IU del sistema de Configuración y dejar de utilizar todas sus funciones?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 82fd6fc..e316a94 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Eliminar de Ajustes"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"¿Eliminar el configurador de IU del sistema de Ajustes y dejar de utilizar sus funciones?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index dd3d823..a151bce 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Eemalda seadetest"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Kas eemaldada seadetest süsteemi kasutajaliidese tuuner ja lõpetada kõikide selle funktsioonide kasutamine?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index a856c09..37cdee7 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Kendu Ezarpenak ataletik"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Sistemako erabiltzaile-interfazearen konfiguratzailea ezarpenetatik kendu nahi duzu, eta haren eginbide guztiak erabiltzeari utzi nahi diozu?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 412f808..80d0918 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"حذف از تنظیمات"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"«تنظیم‌کننده واسط کاربری سیستم» از تنظیمات حذف شود و همه ویژگی‌های آن متوقف شوند؟"</string>
     <string name="activity_not_found" msgid="348423244327799974">"برنامه در دستگاه شما نصب نیست"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"نمایش ثانیه‌های ساعت"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ثانیه‌های ساعت را در نوار وضعیت نشان می‌دهد. ممکن است بر ماندگاری باتری تأثیر بگذارد."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 836b136..b86247a 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Poista Asetuksista"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Haluatko poistaa System UI Tunerin Asetuksista ja lopettaa sen ominaisuuksien käytön?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 8c6773f..f99447c 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Supprimer des paramètres"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Supprimer « System UI Tuner » des paramètres et arrêter d\'utiliser toutes ses fonctionnalités?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 666c0ef..aada1eb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Supprimer l\'outil des paramètres"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Supprimer System UI Tuner des paramètres et arrêter d\'utiliser toutes ses fonctionnalités ?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index d192257..951809f 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Eliminar da Configuración"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Queres eliminar o configurador da IU do sistema da Configuración e deixar de usar todas as súas funcións?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 81dab35..02e4e52 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"સેટિંગ્સમાંથી દૂર કરો"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"સેટિંગ્સમાંથી સિસ્ટમ UI ટ્યૂનર દૂર કરી અને તેની તમામ સુવિધાઓનો ઉપયોગ કરવાનું બંધ કરીએ?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"તમારા ઉપકરણ પર એપ્લિકેશન ઇન્સ્ટોલ થયેલ નથી"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ઘડિયાળ સેકન્ડ બતાવો"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ઘડિયાળ સેકન્ડ સ્થિતિ બારમાં બતાવો. બૅટરીની આવરદા પર અસર કરી શકે છે."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index a4bf691..3ed090c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"सेटिंग से निकालें"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"सेटिंग से सिस्टम UI ट्यूनर निकालें और इसकी सभी सुविधाओं का उपयोग रोक दें?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ऐप्लिकेशन आपके डिवाइस पर इंस्टॉल नहीं है"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"घड़ी के सेकंड दिखाएं"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"स्थिति बार में घड़ी के सेकंड दिखाएं. इससे बैटरी के जीवनकाल पर प्रभाव पड़ सकता है."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d18c04b..9698aba 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -434,4 +434,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Ukloni iz Postavki"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Želite li ukloniti Ugađanje korisničkog sučelja sustava iz Postavki i prestati upotrebljavati njegove značajke?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 49543cb..37cb0a8 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Eltávolítás a Beállítások közül"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Eltávolítja a Kezelőfelület-hangolót a Beállításokból, és nem használja tovább egyik funkcióját sem?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 8cf062f..e31cf49 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Հեռացնել կարգավորումներից"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Հեռացնե՞լ Համակարգի ՕՄ-ի կարգավորիչը կարգավորումներից և չօգտվել այլևս նրա գործառույթներից:"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Հավելվածը տեղադրված չէ սարքի վրա"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Ցույց տալ ժամացույցի վայրկյանները"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Ցույց տալ ժամացույցի վայրկյանները կարգավիճակի տողում: Կարող է ազդել մարտկոցի աշխատանքի ժամանակի վրա:"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6e738de..ad8141b 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Hapus dari Setelan"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Hapus Penyetel Antarmuka Pengguna Sistem dari Setelan dan berhenti menggunakan semua fiturnya?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 4c5bffb..02caf17 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Fjarlægja úr stillingum"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Viltu fjarlægja fínstillingar kerfisviðmóts úr stillingum og hætta að nota eiginleika þeirra?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 75ea3f6..ab5d8be 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Rimuovi dalle impostazioni"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vuoi rimuovere il sintetizzatore interfaccia utente di sistema dalle impostazioni e smettere di utilizzare tutte le sue funzioni?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 4db88bd..9dad8aa 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"הסר מההגדרות"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"‏האם להסיר את System UI Tuner ולהפסיק להשתמש בכל התכונות שלו?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"האפליקציה אינה מותקנת במכשיר"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"הצג שניות בשעון"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"הצג שניות בשעון בשורת הסטטוס. פעולה זו עשויה להשפיע על אורך חיי הסוללה."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index d7b687b..9cb2fc8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -88,7 +88,7 @@
     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"音声アシスト"</string>
     <string name="accessibility_unlock_button" msgid="128158454631118828">"ロック解除"</string>
     <string name="accessibility_unlock_button_fingerprint" msgid="8214125623493923751">"ロック解除ボタン、指紋を待っています"</string>
-    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"指紋を使用せずにロック解除"</string>
+    <string name="accessibility_unlock_without_fingerprint" msgid="7541705575183694446">"指紋認証を使用せずにロック解除"</string>
     <string name="unlock_label" msgid="8779712358041029439">"ロック解除"</string>
     <string name="phone_label" msgid="2320074140205331708">"電話を起動"</string>
     <string name="voice_assist_label" msgid="3956854378310019854">"音声アシストを開く"</string>
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"設定から削除"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"設定からシステムUI調整ツールを削除して、全機能の使用を停止しますか?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"アプリが端末にインストールされていません"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"時計の秒を表示"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ステータスバーに時計の秒を表示します。電池使用量に影響する可能性があります。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 2097996..a9728b2 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"პარამეტრებიდან წაშლა"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"გსურთ სისტემის UI ტუნერის პარამეტრებიდან წაშლა და მისი ყველა ფუნქციის გამოყენების შეწყვეტა?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"აპლიკაცია თქვენს მოწყობილობაზე დაყენებული არ არის"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"საათის წამების ჩვენება"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"საათის წამების ჩვენება სტატუსის ზოლში. შეიძლება გავლენა იქონიოს ბატარეაზე."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index bd49612..1d61372 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Параметрлерден жою"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Жүйелік пайдаланушылық интерфейс тюнерін \"Параметрлер\" тармағынан жойып, оның барлық мүмкіндіктерін пайдалануды тоқтату керек пе?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Қолданба құрылғыда орнатылмаған"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Сағат секундтарын көрсету"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Күйін көрсету жолағында сағат секундтарын көрсету. Батареяның қызмет көрсету мерзіміне әсер етуі мүмкін."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index db5057e..c233f83 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"យកចេញពីការកំណត់"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"យកកម្មវិធីសម្រួល UI ប្រព័ន្ធចេញពីការកំណត់ ហើយឈប់ប្រើលក្ខណៈពិសេសរបស់វាទាំងអស់?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"កម្មវិធីមិនបានដំឡើងនៅលើឧបករណ៍របស់អ្នកទេ"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"បង្ហាញវិនាទី"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"បង្ហាញវិនាទីនៅលើរបារស្ថានភាពអាចនឹងប៉ះពាល់ដល់ថាមពលថ្ម។"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 7d88681..d486e56 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಂದ ತೆಗೆದುಹಾಕಿ"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಂದ ಸಿಸ್ಟಮ್ UI ಟ್ಯೂನರ್ ತೆಗೆದುಹಾಕುವುದೇ ಮತ್ತು ಅದರ ಎಲ್ಲಾ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಬಳಸುವುದನ್ನು ನಿಲ್ಲಿಸುವುದೇ?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ಗಡಿಯಾರದ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ಸ್ಥಿತಿ ಪಟ್ಟಿಯಲ್ಲಿ ಗಡಿಯಾರ ಸೆಕೆಂಡುಗಳನ್ನು ತೋರಿಸು. ಇದಕ್ಕೆ ಬ್ಯಾಟರಿ ಬಾಳಿಕೆಯು ಪರಿಣಾಮಬೀರಬಹುದು."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index af02943..3505754 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"설정에서 삭제"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"시스템 UI 튜너를 설정에서 삭제하고 모든 관련 기능의 사용을 중지하시겠습니까?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"기기에 애플리케이션이 설치되어 있지 않습니다."</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"시계 초 단위 표시"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"상태 표시줄에 시계 초 단위를 표시합니다. 배터리 수명에 영향을 줄 수도 있습니다."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 058cc18..968a65a 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Жөндөөлөрдөн алып салуу"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Жөндөөлөрдөн алынып салынып, анын бардык функциялары токтотулсунбу?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Колдонмо сиздин түзмөгүңүздө орнотулган эмес"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Сааттын секунддары көрсөтүлсүн"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Абал тилкесинен сааттын секунддары көрсөтүлсүн. Батареянын кубаты көбүрөөк сарпталышы мүмкүн."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 3067fb7..f34c70e 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ເອົາອອກ​ຈາກ​ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ເອົາ System UI Tuner ອອກຈາກການຕັ້ງຄ່າ ແລະຢຸດການໃຊ້ທຸກຄຸນສົມບັດໃຊ້ງານຂອງມັນ?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ແອັບ​ພ​ລິ​ເຄ​ຊັນ​ບໍ່​ຖືກ​ຕິດ​ຕັ້ງ​ຢູ່​ໃນ​ອຸ​ປະ​ກອນ​ຂອງ​ທ່ານ"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ສະ​ແດງວິ​ນາ​ທີ​ໂມງ​ຢູ່​ໃນ​ແຖບ​ສະ​ຖາ​ນະ. ອາດ​ຈະ​ມີ​ຜົນ​ກະ​ທົບ​ຕໍ່​ອາ​ຍຸ​ແບັດ​ເຕີ​ຣີ."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index e195444..cf70d6b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Pašalinti iš nustatymų"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Ar norite pašalinti sistemos naudotojo sąsajos derinimo priemonę iš nustatymų ir nebenaudoti jokių jos funkcijų?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 4350876..5e2db80 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -434,4 +434,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Noņemt no iestatījumiem"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vai noņemt sistēmas saskarnes regulatoru no iestatījumiem un pārtraukt izmantot visas tā funkcijas?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 9e7a717..fe781b6 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Отстрани од поставки"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Да се отстрани Адаптерот на УИ на системот од Поставки и да престанат да се користат сите негови функции?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Апликацијата не е инсталирана на уредот"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Прикажи ги секундите на часовникот"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Прикажи ги секундите на часовникот на статусната лента. Може да влијае на траењето на батеријата."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index e941427..6e6fc55 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ക്രമീകരണത്തിൽ നിന്ന് നീക്കംചെയ്യുക"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ക്രമീകരണത്തിൽ നിന്ന് സിസ്റ്റം UI ട്യൂണർ നീക്കംചെയ്യുകയും അതിന്റെ ഫീച്ചറുകളെല്ലാം ഉപയോഗിക്കുന്നത് നിർത്തുകയും ചെയ്യണോ?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"നിങ്ങളുടെ ഉപകരണത്തിൽ അപ്ലിക്കേഷൻ ഇൻസ്റ്റാൾ ചെയ്തിട്ടില്ല"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുക"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"സ്റ്റാറ്റസ് ബാറിൽ ക്ലോക്ക് സെക്കൻഡ് കാണിക്കുന്നത് ബാറ്ററിയുടെ ലൈഫിനെ ബാധിക്കാം."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 69a94c2..65250bb 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -431,4 +431,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Тохиргооноос устгах"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Системийн UI Тохируулагчийг тохиргооноос устгаж, үүнтэй холбоотой бүх тохиргоог ашиглахаа болих уу?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Апп-ыг таны төхөөрөмжид суулгаагүй байна"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Цагийн секундыг харуулах"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 3184de5..0f71b4b 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"सेटिंग्ज मधून काढा"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"सेटिंग्ज मधून सिस्टीम UI ट्यूनर काढून त्याची सर्व वैशिष्ट्‍ये वापरणे थांबवायचे?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"अनुप्रयोग आपल्या डिव्हाइसवर स्थापित केलेला नाही"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"घड्‍याळ सेकंद दर्शवा"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"स्टेटस बारमध्‍ये घड्‍याळ सेकंद दर्शवा. कदाचित बॅटरी आयुष्‍य प्रभावित होऊ शकते."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index b12046b..596275c 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Alih keluar daripada Tetapan"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Alih keluar Penala UI Sistem daripada Tetapan dan berhenti menggunakan semua cirinya?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 6f843b0..3147d0c 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ဆက်တင် အထဲမှ ဖယ်ရှားရန်"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ဆက်တင် အထဲမှ စနစ် UI ဖမ်းစက်ကို ဖယ်ရှားလျက် ၎င်း၏ အင်္ဂါရပ်များ အားလုံး အသုံးပြုမှု ရပ်တန့်ရမလား?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"အပလီကေးရှင်းကို သင်၏ ကိရိယာထဲသို့ တပ်ဆင်မပေးရသေးပါ။"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"နာရီ စက္ကန့်များကို ပြရန်"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"အခြေအနေပြနေရာမှာ နာရီ စက္ကန့်များကို ပြပါ။ ဘက်ထရီ သက်တမ်းကို အကျိုးသက်ရောက်နိုင်တယ်။"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 3a34cdd..f1bfbe1 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Fjern fra Innstillinger"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vil du fjerne System UI Tuner fra Innstillinger og slutte å bruke alle de tilknyttede funksjonene?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 5fadbde..461a15f 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"सेटिङहरूबाट हटाउनुहोस्"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"प्रणाली UI ट्युनर सेटिङहरूबाट हटाउने र यसका सबै सुविधाहरू प्रयोग गर्न रोक्ने हो?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"तपाईँको यन्त्रमा अनुप्रयोग स्थापना भएको छैन"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"घडीमा सेकेन्ड देखाउनुहोस्"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"वस्तुस्थिति पट्टीको घडीमा सेकेन्ड देखाउनुहोस्। ब्याट्री आयु प्रभावित हुन सक्छ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9b7e3409..b74f91d 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Verwijderen uit Instellingen"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Systeem-UI-tuner uit Instellingen verwijderen en het gebruik van alle functies daarvan stopzetten?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 2d70c8a..06746cc 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ਸੈਟਿੰਗਜ਼ ਤੋਂ ਹਟਾਓ"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"ਕੀ ਸੈਟਿੰਗਜ਼ ਤੋਂ ਸਿਸਟਮ UI ਟਿਊਨਰ ਨੂੰ ਹਟਾਉਣਾ ਹੈ ਅਤੇ ਇਸਦੀਆਂ ਸਾਰੀਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਉਪਯੋਗ ਕਰਨ ਤੋਂ ਰੋਕਣਾ ਹੈ?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ਐਪਲੀਕੇਸ਼ਨ ਤੁਹਾਡੀ ਡਿਵਾਈਸ ਤੇ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤੀ ਗਈ ਹੈ"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"ਸਥਿਤੀ ਬਾਰ ਵਿੱਚ ਘੜੀ ਸਕਿੰਟ ਦਿਖਾਓ। ਬੈਟਰੀ ਸਮਰੱਥਾ ਤੇ ਅਸਰ ਪੈ ਸਕਦਾ ਹੈ।"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 93fa170..66100c1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Usuń z Ustawień"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Usunąć Kalibrator System UI z Ustawień i przestać używać wszystkich jego funkcji?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 78eee7b..53cea01 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remover das configurações"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remover sintonizador System UI das configurações e parar de usar todos os seus recursos?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 9c221dd..5006413 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remover das Definições"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Pretende remover o Sintonizador da interface do sistema das Definições e deixar de utilizar todas as respetivas funcionalidades?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 78eee7b..53cea01 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Remover das configurações"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Remover sintonizador System UI das configurações e parar de usar todos os seus recursos?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e9ff595..d97e16b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -434,4 +434,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Eliminați din Setări"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Eliminați System UI Tuner din Setări și încetați utilizarea tuturor funcțiilor sale?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 8691233..d67ad38 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -437,4 +437,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Удалить из настроек"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Убрать функцию System UI Tuner из меню настроек и прекратить ее работу?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Приложение не установлено на вашем устройстве"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Показывать секунды"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Показывать в строке состояния время с точностью до секунды (заряд батареи может расходоваться быстрее)."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 02533f5..06cb626 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"සැකසීම් වෙතින් ඉවත් කරන්න"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"සැකසීම් වෙතින් පද්ධති UI සුසරකය ඉවත් කර සහ එහි සියලු අංග භාවිතය නවත් වන්නද?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"යෙදුම ඔබේ උපාංගය මත ස්ථාපනය කර නැත"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"ඔරලෝසු තත්පර පෙන්වන්න"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"තත්ත්ව තීරුවෙහි ඔරලෝසු තත්පර පෙන්වන්න. බැටරි ආයු කාලයට බලපෑමට හැකිය."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 522d0a6..037074b 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -437,4 +437,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Odstrániť z Nastavení"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Chcete odstrániť tuner používateľského rozhrania systému z Nastavení a prestať používať všetky jeho funkcie?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 770844e..31fe5d8 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Odstrani iz nastavitev"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Ali želite odstraniti Uglaševalnik uporabniškega vmesnika sistema iz nastavitev in prenehati uporabljati vse njegove funkcije?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 1072b54..ffb8bea 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Hiqe nga Cilësimet"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Të hiqet Sintonizuesi i Sistemit të Ndërfaqes së Përdoruesit nga Cilësimet dhe të ndërpritet përdorimi i të gjitha funksioneve të tij?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5df6d62..bae0284 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -434,4 +434,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Уклони из Подешавања"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Желите ли да уклоните Тјунер за кориснички интерфејс система из Подешавања и да престанете да користите све његове функције?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Апликација није инсталирана на уређају"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Приказуј секунде на сату"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Секунде на сату се приказују на статусној траци. То може да утиче на трајање батерије."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 807c53e..6588f10 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Ta bort från inställningarna"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vill du ta bort inställningar för systemgränssnitt från inställningarna och sluta använda alla tillhörande funktioner?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 1bb6c0b..623f12c 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Ondoa kwenye Mipangilio"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Je, ungependa kuondoa Kipokea ishara cha SystemUI kwenye Mipangilio na uache kutumia vipengele vyake vyote?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 8e64e85..c6cb337 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"அமைப்புகளிலிருந்து அகற்று"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"அமைப்புகளிலிருந்து System UI Tunerஐ அகற்றிவிட்டு, அதன் எல்லா அம்சங்களையும் பயன்படுத்துவதை நிறுத்தவா?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"சாதனத்தில் பயன்பாடு நிறுவப்படவில்லை"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"கடிகார வினாடிகளைக் காட்டு"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"நிலைப் பட்டியில் கடிகார வினாடிகளைக் காட்டும். பேட்டரியின் ஆயுளைக் குறைக்கலாம்."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 36b00f8..c0717c1 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"సెట్టింగ్‌ల నుండి తీసివేయి"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"సిస్టమ్ UI ట్యూనర్‌ను సెట్టింగ్‌ల నుండి తీసివేసి, దాని అన్ని లక్షణాలను ఉపయోగించడం ఆపివేయాలా?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"అనువర్తనం మీ పరికరంలో ఇన్‌స్టాల్ చేయలేదు"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"గడియారం సెకన్లు చూపు"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"స్థితి పట్టీలో గడియారం సెకన్లు చూపుతుంది. బ్యాటరీ శక్తి ప్రభావితం చేయవచ్చు."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 0ef2c66..e16fdd2 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"นำออกจากการตั้งค่า"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"นำตัวรับสัญญาณ UI ระบบออกจากการตั้งค่าและหยุดใช้คุณลักษณะทั้งหมดของตัวรับสัญญาณใช่ไหม"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ยังไม่ได้ติดตั้งแอปพลิเคชันบนอุปกรณ์ของคุณ"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"แสดงวินาทีของนาฬิกา"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"แสดงวินาทีของนาฬิกาในแถบสถานะ อาจส่งผลต่ออายุแบตเตอรี"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a208c96..d970084 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Alisin sa Mga Setting"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Alisin ang Tuner ng System UI sa Mga Setting at ihinto ang paggamit ng lahat ng feature nito?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index d359cf1..b22b4fb 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Ayarlar\'dan kaldır"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Sistem Kullanıcı Arayüzü Ayarlayıcısı Ayarlar\'dan kaldırılsın ve tüm özelliklerinin kullanılması durdurulsun mu?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 3e34a1f..898611d 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>
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Видалити з додатка Налаштування"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Видалити інструмент System UI Tuner із додатка Налаштування та припинити користуватися всіма його функціями?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"Додаток не встановлено на вашому пристрої"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"Показувати секунди на годиннику"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"Показувати секунди на годиннику в рядку стану. Акумулятор може розряджатися швидше."</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 650095d..d5683e1 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"ترتیبات سے ہٹائیں"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"‏ترتیبات سے سسٹم UI ٹیونر کو ہٹائیں اور اس کی سبھی خصوصیات کا استعمال بند کریں؟"</string>
     <string name="activity_not_found" msgid="348423244327799974">"ایپلیکیشن آپ کے آلہ پر انسٹال نہیں ہے"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"گھڑی کے سیکنڈز دکھائیں"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"گھڑی کے سیکنڈز اسٹیٹس بار میں دکھائیں۔ اس کا بیٹری کی زندگی پر اثر پڑ سکتا ہے۔"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index e3073bc..e31af6b 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Sozlamalardan olib tashlash"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"System UI Tuner Sozlamalardan olib tashlanib, uning barcha funksiyalaridan foydalanish to‘xtatilsinmi?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 4459497..030bbbe 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Xóa khỏi Cài đặt"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Xóa Bộ điều hướng giao diện người dùng hệ thống khỏi Cài đặt và ngừng sử dụng tất cả tính năng của ứng dụng này?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0272328..b046415 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"从“设置”中移除"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"要将系统界面调谐器从“设置”中移除,并停止使用所有相关功能吗?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"您的设备中未安装此应用"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"显示时钟的秒数"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"在状态栏中显示时钟的秒数。这可能会影响电池的续航时间。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 8adaeac..d568dba 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"從「設定」移除"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"要從「設定」移除系統使用者介面調諧器,並停止其所有功能嗎?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"尚未在裝置安裝應用程式"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數,但可能會影響電池壽命。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 759b585..702ad53 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -435,4 +435,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"從設定中移除"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"要將系統使用者介面調整精靈從設定中移除,並停止使用所有相關功能嗎?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"您的裝置未安裝這個應用程式"</string>
+    <string name="clock_seconds" msgid="7689554147579179507">"顯示時鐘秒數"</string>
+    <string name="clock_seconds_desc" msgid="6282693067130470675">"在狀態列中顯示時鐘秒數。這可能會影響電池續航力。"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 1e7be90..8774036 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -433,4 +433,6 @@
     <string name="remove_from_settings" msgid="8389591916603406378">"Susa kusuka kuzilungiselelo"</string>
     <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Susa isishuni se-UI yesistimu kusuka kuzilungiselelo futhi uyeke ukusebenzisa zonke izici zakhona?"</string>
     <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>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java b/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java
new file mode 100644
index 0000000..e458862
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/analytics/LockedPhoneAnalytics.java
@@ -0,0 +1,453 @@
+/*
+ * 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.analytics;
+
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import com.android.systemui.statusbar.StatusBarState;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+
+/**
+ * Tracks touch, sensor and phone events when the lockscreen is on. If the phone is unlocked
+ * the data containing these events is saved to a file. This data is collected
+ * to analyze how a human interaction looks like.
+ *
+ * A session starts when the screen is turned on.
+ * A session ends when the screen is turned off or user unlocks the phone.
+ */
+public class LockedPhoneAnalytics implements SensorEventListener {
+    private static final String TAG = "LockedPhoneAnalytics";
+    private static final String ANALYTICS_ENABLE = "locked_phone_analytics_enable";
+    private static final String ENFORCE_BOUNCER = "locked_phone_analytics_enforce_bouncer";
+    private static final String COLLECT_BAD_TOCUHES = "locked_phone_analytics_collect_bad_touches";
+
+    private static final long TIMEOUT_MILLIS = 11000; // 11 seconds.
+    public static final boolean DEBUG = false;
+
+    private static final int[] SENSORS = new int[] {
+            Sensor.TYPE_ACCELEROMETER,
+            Sensor.TYPE_GYROSCOPE,
+            Sensor.TYPE_PROXIMITY,
+            Sensor.TYPE_LIGHT,
+            Sensor.TYPE_ROTATION_VECTOR,
+    };
+
+    private final Handler mHandler = new Handler();
+    protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
+        @Override
+        public void onChange(boolean selfChange) {
+            updateConfiguration();
+        }
+    };
+
+    private final SensorManager mSensorManager;
+    private final Context mContext;
+
+    // Err on the side of caution, so logging is not started after a crash even tough the screen
+    // is off.
+    private SensorLoggerSession mCurrentSession = null;
+
+    private boolean mEnableAnalytics = false;
+    private boolean mEnforceBouncer = false;
+    private boolean mTimeoutActive = false;
+    private boolean mCollectBadTouches = false;
+    private boolean mBouncerOn = false;
+    private boolean mCornerSwiping = false;
+    private boolean mTrackingStarted = false;
+
+    private int mState = StatusBarState.SHADE;
+
+    private static LockedPhoneAnalytics sInstance = null;
+
+    private LockedPhoneAnalytics(Context context) {
+        mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
+        mContext = context;
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(ANALYTICS_ENABLE), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(ENFORCE_BOUNCER), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
+
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(COLLECT_BAD_TOCUHES), false,
+                mSettingsObserver,
+                UserHandle.USER_ALL);
+
+        updateConfiguration();
+    }
+
+    public static LockedPhoneAnalytics getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new LockedPhoneAnalytics(context);
+        }
+        return sInstance;
+    }
+
+    private void updateConfiguration() {
+        mEnableAnalytics = Build.IS_DEBUGGABLE && 0 != Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                ANALYTICS_ENABLE, 0);
+        mEnforceBouncer = mEnableAnalytics && 0 != Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                ENFORCE_BOUNCER, 0);
+        mCollectBadTouches = mEnableAnalytics && 0 != Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                COLLECT_BAD_TOCUHES, 0);
+    }
+
+    private boolean sessionEntrypoint() {
+        if ((mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
+                && mEnableAnalytics && mCurrentSession == null) {
+            onSessionStart();
+            return true;
+        }
+        return false;
+    }
+
+    private void sessionExitpoint(int result) {
+        if (mEnableAnalytics && mCurrentSession != null) {
+            onSessionEnd(result);
+        }
+    }
+
+    private void onSessionStart() {
+        mBouncerOn = false;
+        mCornerSwiping = false;
+        mTrackingStarted = false;
+        mCurrentSession = new SensorLoggerSession(System.currentTimeMillis(), System.nanoTime());
+        for (int sensorType : SENSORS) {
+            Sensor s = mSensorManager.getDefaultSensor(sensorType);
+            if (s != null) {
+                mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
+            }
+        }
+    }
+
+    private void onSessionEnd(int result) {
+        SensorLoggerSession session = mCurrentSession;
+        mCurrentSession = null;
+
+        session.end(System.currentTimeMillis(), result);
+        queueSession(session);
+    }
+
+    private void queueSession(final SensorLoggerSession currentSession) {
+        AsyncTask.execute(new Runnable() {
+            @Override
+            public void run() {
+                byte[] b = Session.toByteArray(currentSession.toProto());
+                String dir = mContext.getFilesDir().getAbsolutePath();
+                if (currentSession.getResult() != Session.SUCCESS) {
+                    if (!mCollectBadTouches) {
+                        return;
+                    }
+                    dir += "/bad_touches";
+                } else {
+                    dir += "/good_touches";
+                }
+
+                File file = new File(dir);
+                file.mkdir();
+                File touch = new File(file, "trace_" + System.currentTimeMillis());
+
+                try {
+                    new FileOutputStream(touch).write(b);
+                } catch (IOException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+    }
+
+
+    @Override
+    public synchronized void onSensorChanged(SensorEvent event) {
+        if (mEnableAnalytics && mCurrentSession != null) {
+            mCurrentSession.addSensorEvent(event, System.nanoTime());
+            enforceTimeout();
+        }
+    }
+
+    private void enforceTimeout() {
+        if (mTimeoutActive) {
+            if (System.currentTimeMillis() - mCurrentSession.getStartTimestampMillis()
+                    > TIMEOUT_MILLIS) {
+                onSessionEnd(Session.UNKNOWN);
+                if (DEBUG) {
+                    Log.i(TAG, "Analytics timed out.");
+                }
+            }
+        }
+    }
+
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+    }
+
+    public boolean shouldEnforceBouncer() {
+        return mEnforceBouncer;
+    }
+
+    public void setStatusBarState(int state) {
+        mState = state;
+    }
+
+    public void onScreenOn() {
+        if (sessionEntrypoint()) {
+            if (DEBUG) {
+                Log.d(TAG, "onScreenOn");
+            }
+            addEvent(PhoneEvent.ON_SCREEN_ON);
+        }
+    }
+
+    public void onScreenOnFromTouch() {
+        if (sessionEntrypoint()) {
+            if (DEBUG) {
+                Log.d(TAG, "onScreenOnFromTouch");
+            }
+            addEvent(PhoneEvent.ON_SCREEN_ON_FROM_TOUCH);
+        }
+    }
+
+    public void onScreenOff() {
+        if (DEBUG) {
+            Log.d(TAG, "onScreenOff");
+        }
+        addEvent(PhoneEvent.ON_SCREEN_OFF);
+        sessionExitpoint(Session.FAILURE);
+    }
+
+    public void onSucccessfulUnlock() {
+        if (DEBUG) {
+            Log.d(TAG, "onSuccessfulUnlock");
+        }
+        addEvent(PhoneEvent.ON_SUCCESSFUL_UNLOCK);
+        sessionExitpoint(Session.SUCCESS);
+    }
+
+    public void onBouncerShown() {
+        if (!mBouncerOn) {
+            if (DEBUG) {
+                Log.d(TAG, "onBouncerShown");
+            }
+            mBouncerOn = true;
+            addEvent(PhoneEvent.ON_BOUNCER_SHOWN);
+        }
+    }
+
+    public void onBouncerHidden() {
+        if (mBouncerOn) {
+            if (DEBUG) {
+                Log.d(TAG, "onBouncerHidden");
+            }
+            mBouncerOn = false;
+            addEvent(PhoneEvent.ON_BOUNCER_HIDDEN);
+        }
+    }
+
+    public void onQsDown() {
+        if (DEBUG) {
+            Log.d(TAG, "onQsDown");
+        }
+        addEvent(PhoneEvent.ON_QS_DOWN);
+    }
+
+    public void setQsExpanded(boolean expanded) {
+        if (DEBUG) {
+            Log.d(TAG, "setQsExpanded = " + expanded);
+        }
+        if (expanded) {
+            addEvent(PhoneEvent.SET_QS_EXPANDED_TRUE);
+        } else {
+            addEvent(PhoneEvent.SET_QS_EXPANDED_FALSE);
+        }
+    }
+
+    public void onTrackingStarted() {
+        if (DEBUG) {
+            Log.d(TAG, "onTrackingStarted");
+        }
+        mTrackingStarted = true;
+        addEvent(PhoneEvent.ON_TRACKING_STARTED);
+    }
+
+    public void onTrackingStopped() {
+        if (mTrackingStarted) {
+            if (DEBUG) {
+                Log.d(TAG, "onTrackingStopped");
+            }
+            mTrackingStarted = false;
+            addEvent(PhoneEvent.ON_TRACKING_STOPPED);
+        }
+    }
+
+    public void onNotificationActive() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationActive");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_ACTIVE);
+    }
+
+
+    public void onNotificationDoubleTap() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationDoubleTap");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_DOUBLE_TAP);
+    }
+
+    public void setNotificationExpanded() {
+        if (DEBUG) {
+            Log.d(TAG, "setNotificationExpanded");
+        }
+        addEvent(PhoneEvent.SET_NOTIFICATION_EXPANDED);
+    }
+
+    public void onNotificatonStartDraggingDown() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationStartDraggingDown");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_START_DRAGGING_DOWN);
+    }
+
+    public void onNotificatonStopDraggingDown() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationStopDraggingDown");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_STOP_DRAGGING_DOWN);
+    }
+
+    public void onNotificationDismissed() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationDismissed");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_DISMISSED);
+    }
+
+    public void onNotificatonStartDismissing() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationStartDismissing");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_START_DISMISSING);
+    }
+
+    public void onNotificatonStopDismissing() {
+        if (DEBUG) {
+            Log.d(TAG, "onNotificationStopDismissing");
+        }
+        addEvent(PhoneEvent.ON_NOTIFICATION_STOP_DISMISSING);
+    }
+
+    public void onCameraOn() {
+        if (DEBUG) {
+            Log.d(TAG, "onCameraOn");
+        }
+        addEvent(PhoneEvent.ON_CAMERA_ON);
+    }
+
+    public void onLeftAffordanceOn() {
+        if (DEBUG) {
+            Log.d(TAG, "onLeftAffordanceOn");
+        }
+        addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_ON);
+    }
+
+    public void onAffordanceSwipingStarted(boolean rightCorner) {
+        if (DEBUG) {
+            Log.d(TAG, "onAffordanceSwipingStarted");
+        }
+        mCornerSwiping = true;
+        if (rightCorner) {
+            addEvent(PhoneEvent.ON_RIGHT_AFFORDANCE_SWIPING_STARTED);
+        } else {
+            addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_SWIPING_STARTED);
+        }
+    }
+
+    public void onAffordanceSwipingAborted() {
+        if (mCornerSwiping) {
+            if (DEBUG) {
+                Log.d(TAG, "onAffordanceSwipingAborted");
+            }
+            mCornerSwiping = false;
+            addEvent(PhoneEvent.ON_AFFORDANCE_SWIPING_ABORTED);
+        }
+    }
+
+    public void onUnlockHintStarted() {
+        if (DEBUG) {
+            Log.d(TAG, "onUnlockHintStarted");
+        }
+        addEvent(PhoneEvent.ON_UNLOCK_HINT_STARTED);
+    }
+
+    public void onCameraHintStarted() {
+        if (DEBUG) {
+            Log.d(TAG, "onCameraHintStarted");
+        }
+        addEvent(PhoneEvent.ON_CAMERA_HINT_STARTED);
+    }
+
+    public void onLeftAffordanceHintStarted() {
+        if (DEBUG) {
+            Log.d(TAG, "onLeftAffordanceHintStarted");
+        }
+        addEvent(PhoneEvent.ON_LEFT_AFFORDANCE_HINT_STARTED);
+    }
+
+    public void onTouchEvent(MotionEvent ev, int width, int height) {
+        if (!mBouncerOn && mCurrentSession != null) {
+            if (DEBUG) {
+                Log.v(TAG, "onTouchEvent(ev.action="
+                        + MotionEvent.actionToString(ev.getAction()) + ")");
+            }
+            mCurrentSession.addMotionEvent(ev);
+            mCurrentSession.setTouchArea(width, height);
+            enforceTimeout();
+        }
+    }
+
+    private void addEvent(int eventType) {
+        if (mEnableAnalytics && mCurrentSession != null) {
+            mCurrentSession.addPhoneEvent(eventType, System.nanoTime());
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
new file mode 100644
index 0000000..09383f6a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/analytics/SensorLoggerSession.java
@@ -0,0 +1,160 @@
+/*
+ * 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.analytics;
+
+import android.os.Build;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import java.util.ArrayList;
+
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.TouchEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.SensorEvent;
+import static com.android.systemui.statusbar.phone.TouchAnalyticsProto.Session.PhoneEvent;
+
+/**
+ * Collects touch, sensor and phone events and converts the data to
+ * TouchAnalyticsProto.Session.
+ */
+public class SensorLoggerSession {
+    private static final String TAG = "SensorLoggerSession";
+
+    private final long mStartTimestampMillis;
+    private final long mStartSystemTimeNanos;
+
+    private long mEndTimestampMillis;
+    private int mType;
+
+    private ArrayList<TouchEvent> mMotionEvents = new ArrayList<>();
+    private ArrayList<SensorEvent> mSensorEvents = new ArrayList<>();
+    private ArrayList<PhoneEvent> mPhoneEvents = new ArrayList<>();
+    private int mTouchAreaHeight;
+    private int mTouchAreaWidth;
+    private int mResult = Session.UNKNOWN;
+
+    public SensorLoggerSession(long startTimestampMillis, long startSystemTimeNanos) {
+        mStartTimestampMillis = startTimestampMillis;
+        mStartSystemTimeNanos = startSystemTimeNanos;
+        mType = Session.REAL;
+    }
+
+    public void end(long endTimestampMillis, int result) {
+        mResult = result;
+        mEndTimestampMillis = endTimestampMillis;
+
+        if (LockedPhoneAnalytics.DEBUG) {
+            Log.d(TAG, "Ending session result=" + result + " it lasted for " +
+                    (float) (mEndTimestampMillis - mStartTimestampMillis) / 1000f + "s");
+        }
+    }
+
+    public void addMotionEvent(MotionEvent motionEvent) {
+        TouchEvent event = motionEventToProto(motionEvent);
+        mMotionEvents.add(event);
+    }
+
+    public void addSensorEvent(android.hardware.SensorEvent eventOrig, long systemTimeNanos) {
+        SensorEvent event = sensorEventToProto(eventOrig, systemTimeNanos);
+        mSensorEvents.add(event);
+    }
+
+    public void addPhoneEvent(int eventType, long systemTimeNanos) {
+        PhoneEvent event = phoneEventToProto(eventType, systemTimeNanos);
+        mPhoneEvents.add(event);
+    }
+
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("Session{");
+        sb.append("mStartTimestampMillis=").append(mStartTimestampMillis);
+        sb.append(", mStartSystemTimeNanos=").append(mStartSystemTimeNanos);
+        sb.append(", mEndTimestampMillis=").append(mEndTimestampMillis);
+        sb.append(", mResult=").append(mResult);
+        sb.append(", mTouchAreaHeight=").append(mTouchAreaHeight);
+        sb.append(", mTouchAreaWidth=").append(mTouchAreaWidth);
+        sb.append(", mMotionEvents=[size=").append(mMotionEvents.size()).append("]");
+        sb.append(", mSensorEvents=[size=").append(mSensorEvents.size()).append("]");
+        sb.append(", mPhoneEvents=[size=").append(mPhoneEvents.size()).append("]");
+        sb.append('}');
+        return sb.toString();
+    }
+
+    public Session toProto() {
+        Session proto = new Session();
+        proto.setStartTimestampMillis(mStartTimestampMillis);
+        proto.setDurationMillis(mEndTimestampMillis - mStartTimestampMillis);
+        proto.setBuild(Build.FINGERPRINT);
+        proto.setResult(mResult);
+        proto.setType(mType);
+        proto.sensorEvents = mSensorEvents.toArray(proto.sensorEvents);
+        proto.touchEvents = mMotionEvents.toArray(proto.touchEvents);
+        proto.phoneEvents = mPhoneEvents.toArray(proto.phoneEvents);
+        proto.setTouchAreaWidth(mTouchAreaWidth);
+        proto.setTouchAreaHeight(mTouchAreaHeight);
+        return proto;
+    }
+
+    private PhoneEvent phoneEventToProto(int eventType, long sysTimeNanos) {
+        PhoneEvent proto = new PhoneEvent();
+        proto.setType(eventType);
+        proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
+        return proto;
+    }
+
+    private SensorEvent sensorEventToProto(android.hardware.SensorEvent ev, long sysTimeNanos) {
+        SensorEvent proto = new SensorEvent();
+        proto.setType(ev.sensor.getType());
+        proto.setTimeOffsetNanos(sysTimeNanos - mStartSystemTimeNanos);
+        proto.setTimestamp(ev.timestamp);
+        proto.values = ev.values.clone();
+        return proto;
+    }
+
+    private TouchEvent motionEventToProto(MotionEvent ev) {
+        int count = ev.getPointerCount();
+        TouchEvent proto = new TouchEvent();
+        proto.setTimeOffsetNanos(ev.getEventTimeNano() - mStartSystemTimeNanos);
+        proto.setAction(ev.getActionMasked());
+        proto.setActionIndex(ev.getActionIndex());
+        proto.pointers = new TouchEvent.Pointer[count];
+        for (int i = 0; i < count; i++) {
+            TouchEvent.Pointer p = new TouchEvent.Pointer();
+            p.setX(ev.getX(i));
+            p.setY(ev.getY(i));
+            p.setSize(ev.getSize(i));
+            p.setPressure(ev.getPressure(i));
+            p.setId(ev.getPointerId(i));
+            proto.pointers[i] = p;
+        }
+        return proto;
+    }
+
+    public void setTouchArea(int width, int height) {
+        mTouchAreaWidth = width;
+        mTouchAreaHeight = height;
+    }
+
+    public int getResult() {
+        return mResult;
+    }
+
+    public long getStartTimestampMillis() {
+        return mStartTimestampMillis;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index aafa991..6f49fd6 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -69,6 +69,7 @@
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.FingerprintUnlockController;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@@ -531,7 +532,7 @@
             int currentUser = ActivityManager.getCurrentUser();
             if ((mUpdateMonitor.getUserTrustIsManaged(currentUser)
                     || mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser))
-                    && !mTrustManager.hasUserAuthenticatedSinceBoot(currentUser)) {
+                    && !mUpdateMonitor.getStrongAuthTracker().hasUserAuthenticatedSinceBoot()) {
                 return KeyguardSecurityView.PROMPT_REASON_RESTART;
             } else if (mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser)
                     && mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
@@ -1240,6 +1241,7 @@
                 case START_KEYGUARD_EXIT_ANIM:
                     StartKeyguardExitAnimParams params = (StartKeyguardExitAnimParams) msg.obj;
                     handleStartKeyguardExitAnimation(params.startTime, params.fadeoutDuration);
+                    LockedPhoneAnalytics.getInstance(mContext).onSucccessfulUnlock();
                     break;
                 case KEYGUARD_DONE_PENDING_TIMEOUT:
                     Log.w(TAG, "Timeout while waiting for activity drawn!");
@@ -1459,6 +1461,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)) {
@@ -1472,9 +1483,6 @@
             updateActivityLockScreenState();
             adjustStatusBarLocked();
             sendUserPresentBroadcast();
-            if (mWakeAndUnlocking && mDrawnCallback != null) {
-                notifyDrawn(mDrawnCallback);
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
index 2a84362..adc9b36 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaProjectionPermissionActivity.java
@@ -22,6 +22,7 @@
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
+import android.graphics.Typeface;
 import android.media.projection.MediaProjectionManager;
 import android.media.projection.IMediaProjectionManager;
 import android.media.projection.IMediaProjection;
@@ -29,7 +30,14 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.text.BidiFormatter;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.CompoundButton;
@@ -39,6 +47,8 @@
         implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener,
         DialogInterface.OnCancelListener {
     private static final String TAG = "MediaProjectionPermissionActivity";
+    private static final float MAX_APP_NAME_SIZE_PX = 500f;
+    private static final String ELLIPSIS = "\u2026";
 
     private boolean mPermanentGrant;
     private String mPackageName;
@@ -84,11 +94,49 @@
             return;
         }
 
-        String appName = aInfo.loadLabel(packageManager).toString();
+        TextPaint paint = new TextPaint();
+        paint.setTextSize(42);
+
+        String label = aInfo.loadLabel(packageManager).toString();
+
+        // If the label contains new line characters it may push the security
+        // message below the fold of the dialog. Labels shouldn't have new line
+        // characters anyways, so just truncate the message the first time one
+        // is seen.
+        final int labelLength = label.length();
+        int offset = 0;
+        while (offset < labelLength) {
+            final int codePoint = label.codePointAt(offset);
+            final int type = Character.getType(codePoint);
+            if (type == Character.LINE_SEPARATOR
+                    || type == Character.CONTROL
+                    || type == Character.PARAGRAPH_SEPARATOR) {
+                label = label.substring(0, offset) + ELLIPSIS;
+                break;
+            }
+            offset += Character.charCount(codePoint);
+        }
+
+        if (label.isEmpty()) {
+            label = mPackageName;
+        }
+
+        String unsanitizedAppName = TextUtils.ellipsize(label,
+                paint, MAX_APP_NAME_SIZE_PX, TextUtils.TruncateAt.END).toString();
+        String appName = BidiFormatter.getInstance().unicodeWrap(unsanitizedAppName);
+
+        String actionText = getString(R.string.media_projection_dialog_text, appName);
+        SpannableString message = new SpannableString(actionText);
+
+        int appNameIndex = actionText.indexOf(appName);
+        if (appNameIndex >= 0) {
+            message.setSpan(new StyleSpan(Typeface.BOLD),
+                    appNameIndex, appNameIndex + appName.length(), 0);
+        }
 
         mDialog = new AlertDialog.Builder(this)
                 .setIcon(aInfo.loadIcon(packageManager))
-                .setMessage(getString(R.string.media_projection_dialog_text, appName))
+                .setMessage(message)
                 .setPositiveButton(R.string.media_projection_action_text, this)
                 .setNegativeButton(android.R.string.cancel, this)
                 .setView(R.layout.remember_permission_checkbox)
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 803a014..728d558 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -21,6 +21,7 @@
 import android.media.AudioManager;
 import android.media.MediaPlayer;
 import android.media.MediaPlayer.OnCompletionListener;
+import android.media.MediaPlayer.OnErrorListener;
 import android.net.Uri;
 import android.os.Looper;
 import android.os.PowerManager;
@@ -36,7 +37,7 @@
  * - whenever audio is played, audio focus is requested,
  * - whenever audio playback is stopped or the playback completed, audio focus is abandoned.
  */
-public class NotificationPlayer implements OnCompletionListener {
+public class NotificationPlayer implements OnCompletionListener, OnErrorListener {
     private static final int PLAY = 1;
     private static final int STOP = 2;
     private static final boolean mDebug = false;
@@ -112,6 +113,7 @@
                     //  done playing. This class should be modified to use a single thread, on which
                     //  command are issued, and on which it receives the completion callbacks.
                     player.setOnCompletionListener(NotificationPlayer.this);
+                    player.setOnErrorListener(NotificationPlayer.this);
                     player.start();
                     if (mPlayer != null) {
                         mPlayer.release();
@@ -245,6 +247,13 @@
         }
     }
 
+    public boolean onError(MediaPlayer mp, int what, int extra) {
+        Log.e(mTag, "error " + what + " (extra=" + extra + ") playing notification");
+        // error happened, handle it just like a completion
+        onCompletion(mp);
+        return true;
+    }
+
     private String mTag;
     private CmdThread mThread;
     private CreationAndCompletionThread mCompletionThread;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 7f17885..c1dfec3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -34,6 +34,7 @@
 import android.view.animation.PathInterpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 
 /**
  * Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -128,6 +129,7 @@
     private final int mNormalColor;
     private final int mLowPriorityColor;
     private boolean mIsBelowSpeedBump;
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -151,6 +153,7 @@
                 R.color.notification_ripple_color_low_priority);
         mNormalRippleColor = context.getColor(
                 R.color.notification_ripple_untinted_color);
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     @Override
@@ -219,6 +222,7 @@
                         makeActive();
                         postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
                     } else {
+                        mLockedPhoneAnalytics.onNotificationDoubleTap();
                         boolean performed = performClick();
                         if (performed) {
                             removeCallbacks(mTapTimeoutRunnable);
@@ -238,6 +242,7 @@
     }
 
     private void makeActive() {
+        mLockedPhoneAnalytics.onNotificationActive();
         startActivateAnimation(false /* reverse */);
         mActivated = true;
         if (mOnActivatedListener != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 3a96626..de6c4b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -91,6 +91,7 @@
 import com.android.internal.util.NotificationColorUtil;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.systemui.DejankUtils;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SwipeHelper;
@@ -1624,6 +1625,15 @@
             final PendingIntent intent = sbn.getNotification().contentIntent;
             final String notificationKey = sbn.getKey();
 
+            // Mark notification for one frame.
+            row.setJustClicked(true);
+            DejankUtils.postAfterTraversal(new Runnable() {
+                @Override
+                public void run() {
+                    row.setJustClicked(false);
+                }
+            });
+
             if (NOTIFICATION_CLICK_DEBUG) {
                 Log.d(TAG, "Clicked on content of " + notificationKey);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index d0cd6cb..b01a2a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -64,7 +64,8 @@
     private static final int MSG_APP_TRANSITION_STARTING    = 21 << MSG_SHIFT;
     private static final int MSG_ASSIST_DISCLOSURE          = 22 << MSG_SHIFT;
     private static final int MSG_START_ASSIST               = 23 << MSG_SHIFT;
-    private static final int MSG_SHOW_KEYBOARD_SHORTCUTS    = 24 << MSG_SHIFT;
+    private static final int MSG_CAMERA_LAUNCH_GESTURE      = 24 << MSG_SHIFT;
+    private static final int MSG_SHOW_KEYBOARD_SHORTCUTS    = 25 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -111,6 +112,7 @@
         public void appTransitionStarting(long startTime, long duration);
         public void showAssistDisclosure();
         public void startAssist(Bundle args);
+        public void onCameraLaunchGestureDetected();
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -303,6 +305,14 @@
         }
     }
 
+    @Override
+    public void onCameraLaunchGestureDetected() {
+        synchronized (mList) {
+            mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
+            mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget();
+        }
+    }
+
     private final class H extends Handler {
         public void handleMessage(Message msg) {
             final int what = msg.what & MSG_MASK;
@@ -404,6 +414,9 @@
                 case MSG_START_ASSIST:
                     mCallbacks.startAssist((Bundle) msg.obj);
                     break;
+                case MSG_CAMERA_LAUNCH_GESTURE:
+                    mCallbacks.onCameraLaunchGestureDetected();
+                    break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index 15a092c..e2304c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -29,6 +29,7 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Gefingerpoken;
 import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 
 /**
  * A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
@@ -54,6 +55,7 @@
     private ExpandableView mStartingChild;
     private Interpolator mInterpolator;
     private float mLastHeight;
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
             DragDownCallback dragDownCallback) {
@@ -65,6 +67,7 @@
         mCallback = callback;
         mDragDownCallback = dragDownCallback;
         mHost = host;
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     @Override
@@ -84,6 +87,7 @@
             case MotionEvent.ACTION_MOVE:
                 final float h = y - mInitialTouchY;
                 if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
+                    mLockedPhoneAnalytics.onNotificatonStartDraggingDown();
                     mDraggingDown = true;
                     captureStartingChild(mInitialTouchX, mInitialTouchY);
                     mInitialTouchY = y;
@@ -201,6 +205,7 @@
     }
 
     private void stopDragging() {
+        mLockedPhoneAnalytics.onNotificatonStopDraggingDown();
         if (mStartingChild != null) {
             cancelExpansion(mStartingChild);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index b88e5ca..564a60a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
 import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
@@ -34,6 +35,7 @@
 import android.widget.ImageView;
 
 import com.android.systemui.R;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.stack.NotificationChildrenContainer;
@@ -109,6 +111,9 @@
                     !mChildrenExpanded);
         }
     };
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
+
+    private boolean mJustClicked;
 
     public NotificationContentView getPrivateLayout() {
         return mPrivateLayout;
@@ -301,12 +306,28 @@
         return mHeadsUpHeight;
     }
 
+    /**
+     * Mark whether this notification was just clicked, i.e. the user has just clicked this
+     * notification in this frame.
+     */
+    public void setJustClicked(boolean justClicked) {
+        mJustClicked = justClicked;
+    }
+
+    /**
+     * @return true if this notification has been clicked in this frame, false otherwise
+     */
+    public boolean wasJustClicked() {
+        return mJustClicked;
+    }
+
     public interface ExpansionLogger {
         public void logNotificationExpansion(String key, boolean userAction, boolean expanded);
     }
 
     public ExpandableNotificationRow(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     /**
@@ -494,6 +515,7 @@
      * @param userExpanded whether the user wants this notification to be expanded
      */
     public void setUserExpanded(boolean userExpanded) {
+        mLockedPhoneAnalytics.setNotificationExpanded();
         if (userExpanded && !mExpandable) return;
         final boolean wasExpanded = isExpanded();
         mHasUserChangedExpansion = true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
index 164c496..8058933 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardAffordanceView.java
@@ -36,6 +36,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
+
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.KeyguardAffordanceHelper;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
@@ -79,6 +80,7 @@
     private float mRestingAlpha = KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT;
     private boolean mSupportHardware;
     private boolean mFinishing;
+    private boolean mLaunchingAffordance;
 
     private CanvasProperty<Float> mHwCircleRadius;
     private CanvasProperty<Float> mHwCenterX;
@@ -152,7 +154,7 @@
 
     @Override
     protected void onDraw(Canvas canvas) {
-        mSupportHardware = canvas.isHardwareAccelerated();
+        mSupportHardware = false;//canvas.isHardwareAccelerated();
         drawBackgroundCircle(canvas);
         canvas.save();
         canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2);
@@ -161,9 +163,11 @@
     }
 
     public void setPreviewView(View v) {
+        View oldPreviewView = mPreviewView;
         mPreviewView = v;
         if (mPreviewView != null) {
-            mPreviewView.setVisibility(INVISIBLE);
+            mPreviewView.setVisibility(mLaunchingAffordance
+                    ? oldPreviewView.getVisibility() : INVISIBLE);
         }
     }
 
@@ -176,7 +180,7 @@
     }
 
     private void drawBackgroundCircle(Canvas canvas) {
-        if (mCircleRadius > 0) {
+        if (mCircleRadius > 0 || mFinishing) {
             if (mFinishing && mSupportHardware) {
                 DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
                 displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius,
@@ -207,11 +211,12 @@
         cancelAnimator(mPreviewClipper);
         mFinishing = true;
         mCircleStartRadius = mCircleRadius;
-        float maxCircleSize = getMaxCircleSize();
+        final float maxCircleSize = getMaxCircleSize();
         Animator animatorToRadius;
         if (mSupportHardware) {
             initHwProperties();
             animatorToRadius = getRtAnimatorToRadius(maxCircleSize);
+            startRtAlphaFadeIn();
         } else {
             animatorToRadius = getAnimatorToRadius(maxCircleSize);
         }
@@ -222,6 +227,8 @@
             public void onAnimationEnd(Animator animation) {
                 mAnimationEndRunnable.run();
                 mFinishing = false;
+                mCircleRadius = maxCircleSize;
+                invalidate();
             }
         });
         animatorToRadius.start();
@@ -241,6 +248,36 @@
         }
     }
 
+    /**
+     * Fades in the Circle on the RenderThread. It's used when finishing the circle when it had
+     * alpha 0 in the beginning.
+     */
+    private void startRtAlphaFadeIn() {
+        if (mCircleRadius == 0 && mPreviewView == null) {
+            Paint modifiedPaint = new Paint(mCirclePaint);
+            modifiedPaint.setColor(mCircleColor);
+            modifiedPaint.setAlpha(0);
+            mHwCirclePaint = CanvasProperty.createPaint(modifiedPaint);
+            RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
+                    RenderNodeAnimator.PAINT_ALPHA, 255);
+            animator.setTarget(this);
+            animator.setInterpolator(PhoneStatusBar.ALPHA_IN);
+            animator.setDuration(250);
+            animator.start();
+        }
+    }
+
+    public void instantFinishAnimation() {
+        cancelAnimator(mPreviewClipper);
+        if (mPreviewView != null) {
+            mPreviewView.setClipBounds(null);
+            mPreviewView.setVisibility(View.VISIBLE);
+        }
+        mCircleRadius = getMaxCircleSize();
+        setImageAlpha(0, false);
+        invalidate();
+    }
+
     private void startRtCircleFadeOut(long duration) {
         RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint,
                 RenderNodeAnimator.PAINT_ALPHA, 0);
@@ -443,6 +480,7 @@
     public void setImageAlpha(float alpha, boolean animate, long duration,
             Interpolator interpolator, Runnable runnable) {
         cancelAnimator(mAlphaAnimator);
+        alpha = mLaunchingAffordance ? 0 : alpha;
         int endAlpha = (int) (alpha * 255);
         final Drawable background = getBackground();
         if (!animate) {
@@ -509,4 +547,8 @@
             return false;
         }
     }
+
+    public void setLaunchingAffordance(boolean launchingAffordance) {
+        mLaunchingAffordance = launchingAffordance;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 01aa8d1..8688c28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -86,6 +86,9 @@
         if (mBackground != null) {
             mBackground.setCallback(this);
         }
+        if (mBackground instanceof RippleDrawable) {
+            ((RippleDrawable) mBackground).setForceSoftware(true);
+        }
         invalidate();
     }
 
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 5ec5147..e34c821 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AppInfo.java
@@ -17,24 +17,26 @@
 package com.android.systemui.statusbar.phone;
 
 import android.content.ComponentName;
+import android.os.UserHandle;
 
 /**
  * Navigation bar app information.
  */
 class AppInfo {
     private final ComponentName mComponentName;
-    private final long mUserSerialNumber;
+    private final UserHandle mUser;
 
-    public AppInfo(ComponentName componentName, long userSerialNumber) {
+    public AppInfo(ComponentName componentName, UserHandle user) {
+        if (componentName == null || user == null) throw new IllegalArgumentException();
         mComponentName = componentName;
-        mUserSerialNumber = userSerialNumber;
+        mUser = user;
     }
 
     public ComponentName getComponentName() {
         return mComponentName;
     }
 
-    public long getUserSerialNumber() {
-        return mUserSerialNumber;
+    public UserHandle getUser() {
+        return 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 28d4a42ef..4e69999 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/FingerprintUnlockController.java
@@ -183,8 +183,11 @@
                 mStatusBarKeyguardViewManager.animateCollapsePanels(
                         FINGERPRINT_COLLAPSE_SPEEDUP_FACTOR);
                 break;
-            case MODE_WAKE_AND_UNLOCK:
             case MODE_WAKE_AND_UNLOCK_PULSING:
+                mPhoneStatusBar.updateMediaMetaData(false /* metaDataChanged */);
+                // Fall through.
+            case MODE_WAKE_AND_UNLOCK:
+                mStatusBarWindowManager.setStatusBarFocusable(false);
                 mDozeScrimController.abortPulsing();
                 mKeyguardViewMediator.onWakeAndUnlocking();
                 mScrimController.setWakeAndUnlocking();
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 076378e..f46d1a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/GetActivityIconTask.java
@@ -16,20 +16,21 @@
 
 package com.android.systemui.statusbar.phone;
 
-import android.content.ComponentName;
+import android.app.AppGlobals;
+import android.content.pm.ActivityInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.graphics.drawable.Drawable;
 import android.os.AsyncTask;
+import android.os.RemoteException;
 import android.util.Slog;
-import android.view.View;
 import android.widget.ImageView;
 
 /**
  * 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<ComponentName, Void, Drawable> {
+class GetActivityIconTask extends AsyncTask<AppInfo, Void, Drawable> {
     private final static String TAG = "GetActivityIconTask";
 
     private final PackageManager mPackageManager;
@@ -43,15 +44,27 @@
     }
 
     @Override
-    protected Drawable doInBackground(ComponentName... params) {
+    protected Drawable doInBackground(AppInfo... params) {
         if (params.length != 1) {
             throw new IllegalArgumentException("Expected one parameter");
         }
-        ComponentName activityName = params[0];
+        AppInfo appInfo = params[0];
         try {
-            return mPackageManager.getActivityIcon(activityName);
-        } catch (NameNotFoundException e) {
-            Slog.w(TAG, "Icon not found for " + activityName);
+            IPackageManager mPM = AppGlobals.getPackageManager();
+            ActivityInfo ai = mPM.getActivityInfo(
+                    appInfo.getComponentName(),
+                    0,
+                    appInfo.getUser().getIdentifier());
+
+            if (ai == null) {
+                Slog.w(TAG, "Icon not found for " + appInfo);
+                return null;
+            }
+
+            Drawable unbadgedIcon = ai.loadIcon(mPackageManager);
+            return mPackageManager.getUserBadgedIcon(unbadgedIcon, appInfo.getUser());
+        } 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/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 10019f9..60ebfdf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -86,9 +86,9 @@
         mContext = context;
         mCallback = callback;
         initIcons();
-        updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true);
-        updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false, true);
-        updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true);
+        updateIcon(mLeftIcon, 0.0f, mLeftIcon.getRestingAlpha(), false, false, true, false);
+        updateIcon(mCenterIcon, 0.0f, mCenterIcon.getRestingAlpha(), false, false, true, false);
+        updateIcon(mRightIcon, 0.0f, mRightIcon.getRestingAlpha(), false, false, true, false);
         initDimens();
     }
 
@@ -144,9 +144,7 @@
                 } else {
                     mTouchSlopExeeded = false;
                 }
-                mCallback.onSwipingStarted(targetView == mRightIcon);
-                mSwipingInProgress = true;
-                mTargetedView = targetView;
+                startSwiping(targetView);
                 mInitialTouchX = x;
                 mInitialTouchY = y;
                 mTranslationOnDown = mTranslation;
@@ -192,6 +190,12 @@
         return true;
     }
 
+    private void startSwiping(View targetView) {
+        mCallback.onSwipingStarted(targetView == mRightIcon);
+        mSwipingInProgress = true;
+        mTargetedView = targetView;
+    }
+
     private View getIconAtPosition(float x, float y) {
         if (leftSwipePossible() && isOnIcon(mLeftIcon, x, y)) {
             return mLeftIcon;
@@ -324,7 +328,7 @@
         boolean velIsInWrongDirection = vel * mTranslation < 0;
         snapBack |= Math.abs(vel) > mMinFlingVelocity && velIsInWrongDirection;
         vel = snapBack ^ velIsInWrongDirection ? 0 : vel;
-        fling(vel, snapBack || forceSnapBack);
+        fling(vel, snapBack || forceSnapBack, mTranslation < 0);
     }
 
     private boolean isBelowFalsingThreshold() {
@@ -336,9 +340,8 @@
         return (int) (mMinTranslationAmount * factor);
     }
 
-    private void fling(float vel, final boolean snapBack) {
-        float target = mTranslation < 0
-                ? -mCallback.getMaxTranslationDistance()
+    private void fling(float vel, final boolean snapBack, boolean right) {
+        float target = right ? -mCallback.getMaxTranslationDistance()
                 : mCallback.getMaxTranslationDistance();
         target = snapBack ? 0 : target;
 
@@ -352,8 +355,8 @@
         });
         animator.addListener(mFlingEndListener);
         if (!snapBack) {
-            startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable);
-            mCallback.onAnimationToSideStarted(mTranslation < 0, mTranslation, vel);
+            startFinishingCircleAnimation(vel * 0.375f, mAnimationEndRunnable, right);
+            mCallback.onAnimationToSideStarted(right, mTranslation, vel);
         } else {
             reset(true);
         }
@@ -364,8 +367,9 @@
         }
     }
 
-    private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable) {
-        KeyguardAffordanceView targetView = mTranslation > 0 ? mLeftIcon : mRightIcon;
+    private void startFinishingCircleAnimation(float velocity, Runnable mAnimationEndRunnable,
+            boolean right) {
+        KeyguardAffordanceView targetView = right ? mRightIcon : mLeftIcon;
         targetView.finishAnimation(velocity, mAnimationEndRunnable);
     }
 
@@ -383,19 +387,20 @@
             fadeOutAlpha = Math.max(fadeOutAlpha, 0.0f);
 
             boolean animateIcons = isReset && animateReset;
+            boolean forceNoCircleAnimation = isReset && !animateReset;
             float radius = getRadiusFromTranslation(absTranslation);
             boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
                 updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
-                        false, false, false);
+                        false, false, false, false);
             } else {
                 updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
-                        animateIcons, slowAnimation, false);
+                        animateIcons, slowAnimation, false, forceNoCircleAnimation);
             }
             updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
-                    animateIcons, slowAnimation, false);
+                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
             updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
-                    animateIcons, slowAnimation, false);
+                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
 
             mTranslation = translation;
         }
@@ -431,16 +436,21 @@
 
     public void animateHideLeftRightIcon() {
         cancelAnimation();
-        updateIcon(mRightIcon, 0f, 0f, true, false, false);
-        updateIcon(mLeftIcon, 0f, 0f, true, false, false);
+        updateIcon(mRightIcon, 0f, 0f, true, false, false, false);
+        updateIcon(mLeftIcon, 0f, 0f, true, false, false, false);
     }
 
     private void updateIcon(KeyguardAffordanceView view, float circleRadius, float alpha,
-            boolean animate, boolean slowRadiusAnimation, boolean force) {
+                            boolean animate, boolean slowRadiusAnimation, boolean force,
+                            boolean forceNoCircleAnimation) {
         if (view.getVisibility() != View.VISIBLE && !force) {
             return;
         }
-        view.setCircleRadius(circleRadius, slowRadiusAnimation);
+        if (forceNoCircleAnimation) {
+            view.setCircleRadiusWithoutAnimation(circleRadius);
+        } else {
+            view.setCircleRadius(circleRadius, slowRadiusAnimation);
+        }
         updateIconAlpha(view, alpha, animate);
     }
 
@@ -503,8 +513,36 @@
         mMotionCancelled = true;
         if (mSwipingInProgress) {
             mCallback.onSwipingAborted();
+            mSwipingInProgress = false;
         }
-        mSwipingInProgress = false;
+    }
+
+    public boolean isSwipingInProgress() {
+        return mSwipingInProgress;
+    }
+
+    public void launchAffordance(boolean animate, boolean left) {
+        if (mSwipingInProgress) {
+            // We don't want to mess with the state if the user is actually swiping already.
+            return;
+        }
+        KeyguardAffordanceView targetView = left ? mLeftIcon : mRightIcon;
+        KeyguardAffordanceView otherView = left ? mRightIcon : mLeftIcon;
+        startSwiping(targetView);
+        if (animate) {
+            fling(0, false, !left);
+            updateIcon(otherView, 0.0f, 0, true, false, true, false);
+            updateIcon(mCenterIcon, 0.0f, 0, true, false, true, false);
+        } else {
+            mCallback.onAnimationToSideStarted(!left, mTranslation, 0);
+            mTranslation = left ? mCallback.getMaxTranslationDistance()
+                    : mCallback.getMaxTranslationDistance();
+            updateIcon(mCenterIcon, 0.0f, 0.0f, false, false, true, false);
+            updateIcon(otherView, 0.0f, 0.0f, false, false, true, false);
+            targetView.instantFinishAnimation();
+            mFlingEndListener.onAnimationEnd(null);
+            mAnimationEndRunnable.run();
+        }
     }
 
     public interface Callback {
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 4da9acd..d30411a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -80,7 +80,7 @@
     private static final Intent SECURE_CAMERA_INTENT =
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
                     .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-    private static final Intent INSECURE_CAMERA_INTENT =
+    public static final Intent INSECURE_CAMERA_INTENT =
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
     private static final Intent PHONE_INTENT = new Intent(Intent.ACTION_DIAL);
     private static final int DOZE_ANIMATION_STAGGER_DELAY = 48;
@@ -649,7 +649,7 @@
         }
 
         @Override
-        public void onStrongAuthTimeoutExpiredChanged(int userId) {
+        public void onStrongAuthStateChanged(int userId) {
             mLockIcon.update();
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index 8b96e5f..cbd23bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -31,6 +31,7 @@
 import com.android.keyguard.R;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 
 import static com.android.keyguard.KeyguardHostView.OnDismissAction;
 import static com.android.keyguard.KeyguardSecurityModel.SecurityMode;
@@ -49,10 +50,11 @@
     private ViewGroup mRoot;
     private boolean mShowingSoon;
     private int mBouncerPromptReason;
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
             new KeyguardUpdateMonitorCallback() {
                 @Override
-                public void onStrongAuthTimeoutExpiredChanged(int userId) {
+                public void onStrongAuthStateChanged(int userId) {
                     mBouncerPromptReason = mCallback.getBouncerPromptReason();
                 }
             };
@@ -66,9 +68,11 @@
         mContainer = container;
         mWindowManager = windowManager;
         KeyguardUpdateMonitor.getInstance(mContext).registerCallback(mUpdateMonitorCallback);
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
     }
 
     public void show(boolean resetSecuritySelection) {
+        mLockedPhoneAnalytics.onBouncerShown();
         ensureView();
         if (resetSecuritySelection) {
             // showPrimarySecurityScreen() updates the current security method. This is needed in
@@ -128,6 +132,7 @@
     }
 
     public void hide(boolean destroyView) {
+        mLockedPhoneAnalytics.onBouncerHidden();
         cancelShowRunnable();
          if (mKeyguardView != null) {
             mKeyguardView.cancelDismissAction();
@@ -157,6 +162,7 @@
     public void reset() {
         cancelShowRunnable();
         inflateView();
+        mLockedPhoneAnalytics.onBouncerHidden();
     }
 
     public void onScreenTurnedOff() {
@@ -244,6 +250,7 @@
 
             // We need to show it in case it is secure. If not, it will get dismissed in any case.
             mRoot.setVisibility(View.VISIBLE);
+            mLockedPhoneAnalytics.onBouncerShown();
             mKeyguardView.requestFocus();
             mKeyguardView.onResume();
             return true;
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..93ecb06 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();
     }
@@ -208,6 +220,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,10 +241,10 @@
         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 (mUnlockMethodCache.canSkipBouncer()) {
+            return STATE_LOCK_OPEN;
         } else if (fingerprintRunning && unlockingAllowed) {
             return STATE_FINGERPRINT;
         } else if (mUnlockMethodCache.isFaceUnlockRunning()) {
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 cb5c125..5c01f01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -28,14 +28,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.Slog;
 import android.view.DragEvent;
 import android.view.LayoutInflater;
@@ -48,6 +46,7 @@
 import com.android.internal.content.PackageMonitor;
 import com.android.systemui.R;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -77,14 +76,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 long mCurrentUserSerialNumber = -1;
+    private ImageView mDragView;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
@@ -93,15 +90,23 @@
             if (Intent.ACTION_USER_SWITCHED.equals(action)) {
                 int currentUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
                 onUserSwitched(currentUserId);
+            } else if (Intent.ACTION_MANAGED_PROFILE_REMOVED.equals(action)) {
+                UserHandle removedProfile = intent.getParcelableExtra(Intent.EXTRA_USER);
+                onManagedProfileRemoved(removedProfile);
             }
         }
     };
 
-    public NavigationBarApps(Context context, AttributeSet attrs) {
-        super(context, attrs);
+    public static NavigationBarAppsModel getModel(Context context) {
         if (sAppsModel == null) {
             sAppsModel = new NavigationBarAppsModel(context);
         }
+        return sAppsModel;
+    }
+
+    public NavigationBarApps(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        getModel(context);
         mPackageManager = context.getPackageManager();
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
         mLayoutInflater = LayoutInflater.from(context);
@@ -173,21 +178,24 @@
     }
 
     private void removeIfUnlauncheable(String packageName, UserHandle user) {
-        long appUserSerialNumber = mUserManager.getSerialNumberForUser(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);
-            if (appInfo.getUserSerialNumber() != appUserSerialNumber) continue;
+        for(int i = getChildCount() - 1; i >= 0; --i) {
+            View child = getChildAt(i);
+            AppInfo appInfo = (AppInfo)child.getTag();
+            if (appInfo == null) continue;  // Skip the drag placeholder.
+            if (!appInfo.getUser().equals(user)) continue;
 
             ComponentName appComponentName = appInfo.getComponentName();
             if (!appComponentName.getPackageName().equals(packageName)) continue;
 
-            if (sAppsModel.buildAppLaunchIntent(appComponentName, user) != null) continue;
+            if (sAppsModel.buildAppLaunchIntent(appInfo) != null) {
+                continue;
+            }
 
             removeViewAt(i);
-            sAppsModel.removeApp(i);
-            sAppsModel.savePrefs();
+        }
+        if (getChildCount() != sAppsModel.getApps().size()) {
+            saveApps();
         }
     }
 
@@ -206,14 +214,12 @@
         transition.enableTransitionType(LayoutTransition.CHANGING);
         parent.setLayoutTransition(transition);
 
-        int currentUserId = ActivityManager.getCurrentUser();
-        mCurrentUserSerialNumber = mUserManager.getSerialNumberForUser(
-                new UserHandle(currentUserId));
-        sAppsModel.setCurrentUser(currentUserId);
+        sAppsModel.setCurrentUser(ActivityManager.getCurrentUser());
         recreateAppButtons();
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_USER_SWITCHED);
+        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
         mContext.registerReceiver(mBroadcastReceiver, filter);
 
         mAppPackageMonitor.register(mContext, null, UserHandle.ALL, true);
@@ -234,31 +240,48 @@
         // 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();
+            AppInfo app = apps.get(i);
+            ImageView button = createAppButton(app);
             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.getComponentName());
+            new GetActivityIconTask(mPackageManager, button).execute(app);
         }
     }
 
     /**
+     * Saves apps stored in app icons into the data model.
+     */
+    private void saveApps() {
+        List<AppInfo> apps = new ArrayList<AppInfo>();
+        int childCount = getChildCount();
+        for (int i = 0; i != childCount; ++i) {
+            View child = getChildAt(i);
+            AppInfo appInfo = (AppInfo)child.getTag();
+            if (appInfo == null) continue;  // Skip the drag placeholder.
+            apps.add(appInfo);
+        }
+        sAppsModel.setApps(apps);
+    }
+
+    /**
      * Creates a new ImageView for a launcher activity, inflated from
      * R.layout.navigation_bar_app_item.
      */
-    private ImageView createAppButton() {
+    private ImageView createAppButton(AppInfo appInfo) {
         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(appInfo);
         return button;
     }
 
@@ -266,10 +289,9 @@
     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;
+            AppInfo app = (AppInfo) v.getTag();
+            startAppDrag(mDragView, app);
             return true;
         }
     }
@@ -280,7 +302,7 @@
      */
     @Nullable
     static CharSequence getAppLabel(PackageManager packageManager,
-            ComponentName activityName) {
+                                    ComponentName activityName) {
         String packageName = activityName.getPackageName();
         ApplicationInfo info;
         try {
@@ -296,7 +318,10 @@
     static void startAppDrag(ImageView icon, AppInfo appInfo) {
         // The drag data is an Intent to launch the activity.
         Intent mainIntent = Intent.makeMainActivity(appInfo.getComponentName());
-        mainIntent.putExtra(EXTRA_PROFILE, appInfo.getUserSerialNumber());
+        UserManager userManager =
+                (UserManager) icon.getContext().getSystemService(Context.USER_SERVICE);
+        long userSerialNumber = userManager.getSerialNumberForUser(appInfo.getUser());
+        mainIntent.putExtra(EXTRA_PROFILE, userSerialNumber);
         ClipData dragData = ClipData.newIntent("", mainIntent);
         // Use the ImageView to create the shadow.
         View.DragShadowBuilder shadow = new AppIconDragShadowBuilder(icon);
@@ -370,13 +395,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;
     }
 
@@ -401,7 +424,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
@@ -411,10 +433,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) {
@@ -425,23 +443,21 @@
             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.
         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;
         }
 
-        // The drop had valid data. Update the placeholder with a real activity and icon.
-        updateAppAt(dragViewIndex, appInfo);
+        // If this was an existing app being dragged then end the drag.
+        if (mDragView.getTag() != null) {
+            endDrag();
+            return true;
+        }
+
+        // The drop had valid data. Convert the placeholder to a real icon.
+        updateApp(mDragView, appInfo);
         endDrag();
         return true;
     }
@@ -450,7 +466,7 @@
     private void endDrag() {
         mDragView.setVisibility(View.VISIBLE);
         mDragView = null;
-        sAppsModel.savePrefs();
+        saveApps();
     }
 
     /** Returns an app info from a DragEvent, or null if the data wasn't valid. */
@@ -462,38 +478,46 @@
         if (data.getItemCount() != 1) {
             return null;
         }
-        Intent intent = data.getItemAt(0).getIntent();
+        ClipData.Item item = data.getItemAt(0);
+        if (item == null) {
+            return null;
+        }
+        Intent intent = item.getIntent();
         if (intent == null) {
             return null;
         }
-
         long userSerialNumber = intent.getLongExtra(EXTRA_PROFILE, -1);
-
-        // Validate the received user serial number.
+        if (userSerialNumber == -1) {
+            return null;
+        }
         UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
         if (appUser == null) {
-            userSerialNumber = mCurrentUserSerialNumber;
+            return null;
         }
-
-        return new AppInfo(intent.getComponent(), userSerialNumber);
+        ComponentName componentName = intent.getComponent();
+        if (componentName == null) {
+            return null;
+        }
+        AppInfo appInfo = new AppInfo(componentName, appUser);
+        if (sAppsModel.buildAppLaunchIntent(appInfo) == null) {
+            return null;
+        }
+        return appInfo;
     }
 
     /** 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.getComponentName());
+    private void updateApp(ImageView button, AppInfo appInfo) {
+        button.setTag(appInfo);
+        new GetActivityIconTask(mPackageManager, button).execute(appInfo);
     }
 
-    /** 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);
+        removeView(mDragView);
         endDrag();
     }
 
@@ -539,21 +563,11 @@
     private class AppClickListener implements View.OnClickListener {
         @Override
         public void onClick(View v) {
-            AppInfo appInfo = sAppsModel.getApp(indexOfChild(v));
-            ComponentName component = appInfo.getComponentName();
-
-            long appUserSerialNumber = appInfo.getUserSerialNumber();
-            UserHandle appUser = mUserManager.getUserForSerialNumber(appUserSerialNumber);
-            if (appUser == null) {
-                Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
-                Log.e(TAG, "Can't start activity " + component +
-                        " because its user doesn't exist.");
-                return;
-            }
-
-            Intent launchIntent = sAppsModel.buildAppLaunchIntent(component, appUser);
+            AppInfo appInfo = (AppInfo)v.getTag();
+            Intent launchIntent = sAppsModel.buildAppLaunchIntent(appInfo);
             if (launchIntent == null) {
-                Toast.makeText(getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
+                Toast.makeText(
+                        getContext(), R.string.activity_not_found, Toast.LENGTH_SHORT).show();
                 return;
             }
 
@@ -568,18 +582,26 @@
             Bundle optsBundle = opts.toBundle();
             launchIntent.setSourceBounds(sourceBounds);
 
-            mContext.startActivityAsUser(launchIntent, optsBundle, appUser);
+            mContext.startActivityAsUser(launchIntent, optsBundle, appInfo.getUser());
         }
     }
 
     private void onUserSwitched(int currentUserId) {
-        final long newUserSerialNumber =
-                mUserManager.getSerialNumberForUser(new UserHandle(currentUserId));
+        sAppsModel.setCurrentUser(currentUserId);
+        recreateAppButtons();
+    }
 
-        if (newUserSerialNumber != mCurrentUserSerialNumber) {
-            mCurrentUserSerialNumber = newUserSerialNumber;
-            sAppsModel.setCurrentUser(currentUserId);
-            recreateAppButtons();
+    private void onManagedProfileRemoved(UserHandle removedProfile) {
+        for(int i = getChildCount() - 1; i >= 0; --i) {
+            View view = getChildAt(i);
+            AppInfo appInfo = (AppInfo)view.getTag();
+            if (appInfo == null) return;  // Skip the drag placeholder.
+            if (!appInfo.getUser().equals(removedProfile)) continue;
+
+            removeViewAt(i);
+        }
+        if (getChildCount() != sAppsModel.getApps().size()) {
+            saveApps();
         }
     }
 }
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 c4c31fd..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;
@@ -106,9 +105,24 @@
         return AppGlobals.getPackageManager();
     }
 
-    // Returns a launch intent for a given component, or null if the component is unlauncheable.
-    public Intent buildAppLaunchIntent(ComponentName component, UserHandle appUser) {
-        int appUserId = appUser.getIdentifier();
+    // Returns a launch intent for a given app info, or null if the app info is unlauncheable.
+    public Intent buildAppLaunchIntent(AppInfo appInfo) {
+        ComponentName component = appInfo.getComponentName();
+        int appUserId = appInfo.getUser().getIdentifier();
+
+        if (mCurrentUserId != appUserId) {
+            // Check if app user is a profile of current user and the app user is enabled.
+            UserInfo appUserInfo = mUserManager.getUserInfo(appUserId);
+            UserInfo currentUserInfo = mUserManager.getUserInfo(mCurrentUserId);
+            if (appUserInfo == null || currentUserInfo == null
+                    || appUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
+                    || appUserInfo.profileGroupId != currentUserInfo.profileGroupId
+                    || !appUserInfo.isEnabled()) {
+                Slog.e(TAG, "User " + appUserId +
+                        " is is not a profile of the current user, or is disabled.");
+                return null;
+            }
+        }
 
         // This code is based on LauncherAppsService.startActivityAsUser code.
         Intent launchIntent = new Intent(Intent.ACTION_MAIN);
@@ -119,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;
         }
 
@@ -149,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;
     }
 
@@ -164,7 +178,7 @@
 
         int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
         if (appCount >= 0) {
-            loadAppsFromPrefs();
+            loadAppsFromPrefs(appCount);
         } else {
             // We switched to this user for the first time ever. This is a good opportunity to clean
             // prefs for users deleted in the past.
@@ -216,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);
@@ -250,42 +250,52 @@
             final AppInfo appInfo = mApps.get(i);
             String componentNameString = appInfo.getComponentName().flattenToString();
             edit.putString(prefNameForApp(i), componentNameString);
-            edit.putLong(prefUserForApp(i), appInfo.getUserSerialNumber());
+            long userSerialNumber = mUserManager.getSerialNumberForUser(appInfo.getUser());
+            edit.putLong(prefUserForApp(i), userSerialNumber);
         }
         // Start an asynchronous disk write.
         edit.apply();
     }
 
+    /** Loads AppInfo from prefs. Returns null if something is wrong. */
+    private AppInfo loadAppFromPrefs(int index) {
+        String prefValue = mPrefs.getString(prefNameForApp(index), null);
+        if (prefValue == null) {
+            Slog.w(TAG, "Couldn't find pref " + prefNameForApp(index));
+            return null;
+        }
+        ComponentName componentName = ComponentName.unflattenFromString(prefValue);
+        if (componentName == null) {
+            Slog.w(TAG, "Invalid component name " + prefValue);
+            return null;
+        }
+        long userSerialNumber = mPrefs.getLong(prefUserForApp(index), -1);
+        if (userSerialNumber == -1) {
+            Slog.w(TAG, "Couldn't find pref " + prefUserForApp(index));
+            return null;
+        }
+        UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
+        if (appUser == null) {
+            Slog.w(TAG, "No user for serial " + userSerialNumber);
+            return null;
+        }
+        AppInfo appInfo = new AppInfo(componentName, appUser);
+        if (buildAppLaunchIntent(appInfo) == null) {
+            return null;
+        }
+        return appInfo;
+    }
+
     /** Loads the list of apps from SharedPreferences. */
-    private void loadAppsFromPrefs() {
-        UserManager mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
-        boolean hadUnlauncheableApps = false;
-
-        int appCount = mPrefs.getInt(userPrefixed(APP_COUNT_PREF), -1);
+    private void loadAppsFromPrefs(int appCount) {
         for (int i = 0; i < appCount; i++) {
-            String prefValue = mPrefs.getString(prefNameForApp(i), null);
-            if (prefValue == null) {
-                Slog.w(TAG, "Couldn't find pref " + prefNameForApp(i));
-                // Couldn't find the saved state. Just skip this item.
-                continue;
-            }
-            ComponentName componentName = ComponentName.unflattenFromString(prefValue);
-            long userSerialNumber = mPrefs.getLong(prefUserForApp(i), -1);
-            if (userSerialNumber == -1) {
-                Slog.w(TAG, "Couldn't find pref " + prefUserForApp(i));
-                // Couldn't find the saved state. Just skip this item.
-                continue;
-            }
-            UserHandle appUser = mUserManager.getUserForSerialNumber(userSerialNumber);
-            if (appUser != null && buildAppLaunchIntent(componentName, appUser) != null) {
-                mApps.add(new AppInfo(componentName, userSerialNumber));
-            } else {
-                hadUnlauncheableApps = true;
+            AppInfo appInfo = loadAppFromPrefs(i);
+            if (appInfo != null) {
+                mApps.add(appInfo);
             }
         }
 
-        if (hadUnlauncheableApps) savePrefs();
+        if (appCount != mApps.size()) savePrefs();
     }
 
     /** Adds the first few apps from the owner profile. Used for demo purposes. */
@@ -301,7 +311,7 @@
             ResolveInfo ri = apps.get(i);
             ComponentName componentName = new ComponentName(
                     ri.activityInfo.packageName, ri.activityInfo.name);
-            mApps.add(new AppInfo(componentName, mCurrentUserSerialNumber));
+            mApps.add(new AppInfo(componentName, new UserHandle(mCurrentUserId)));
         }
 
         savePrefs();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
index b024ec4..7ff56ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarRecents.java
@@ -25,10 +25,10 @@
 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.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
@@ -151,7 +151,7 @@
         button.setOnLongClickListener(mAppLongClickListener);
         addView(button);
 
-        ComponentName activityName = getRealActivityForTask(task);
+        ComponentName activityName = getActivityForTask(task);
         CharSequence appLabel = NavigationBarApps.getAppLabel(mPackageManager, activityName);
         button.setContentDescription(appLabel);
 
@@ -160,7 +160,8 @@
 
         button.setVisibility(View.VISIBLE);
         // Load the activity icon on a background thread.
-        new GetActivityIconTask(mPackageManager, button).execute(getRealActivityForTask(task));
+        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() {
@@ -171,14 +172,25 @@
                 try {
                     manager.startActivityFromRecents(taskPersistentId, null /* options */);
                 } catch (RemoteException e) {
-                    e.printStackTrace();
+                    Slog.e(TAG, "Exception when activating a recent task", e);
+                } catch (IllegalArgumentException e) {
+                    Slog.e(TAG, "Exception when activating a recent task", e);
                 }
             }
         });
     }
 
-    private static ComponentName getRealActivityForTask(RecentTaskInfo task) {
-        // Prefer the activity that started the task.
+    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;
         }
@@ -218,6 +230,35 @@
             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) {
+                Slog.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;
@@ -225,18 +266,28 @@
             // 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();
-            Intent intent = mContext.getPackageManager().getLaunchIntentForPackage(packageName);
-            if (intent == null) {
-                return false;
+            ComponentName componentName = getActivityForTask(task);
+            UserHandle taskUser = new UserHandle(task.userId);
+            AppInfo appInfo = new AppInfo(componentName, taskUser);
+
+            if (NavigationBarApps.getModel(mContext).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 false;
+                }
+
+                appInfo = new AppInfo(component, taskUser);
             }
 
-            if (DEBUG) Slog.d(TAG, "Start drag with " + intent);
+            if (DEBUG) {
+                Slog.d(TAG, "Start drag with " + appInfo.getComponentName().flattenToString());
+            }
 
-            UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-            long userSerialNumber = userManager.getSerialNumberForUser(new UserHandle(task.userId));
-            NavigationBarApps.startAppDrag(
-                    icon, new AppInfo(intent.getComponent(), userSerialNumber));
+            NavigationBarApps.startAppDrag(icon, appInfo);
             return true;
         }
     }
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 3c3c325..3ad7246 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
@@ -203,6 +204,8 @@
     private int mLastOrientation = -1;
     private boolean mClosingWithAlphaFadeOut;
     private boolean mHeadsUpAnimatingAway;
+    private boolean mLaunchingAffordance;
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
         @Override
@@ -219,6 +222,7 @@
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setWillNotDraw(!DEBUG);
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     public void setStatusBar(PhoneStatusBar bar) {
@@ -488,7 +492,9 @@
         mIsLaunchTransitionFinished = false;
         mBlockTouches = false;
         mUnlockIconActive = false;
-        mAfforanceHelper.reset(true);
+        if (!mLaunchingAffordance) {
+            mAfforanceHelper.reset(false);
+        }
         closeQs();
         mStatusBar.dismissPopups();
         mNotificationStackScroller.setOverScrollAmount(0f, true /* onTop */, false /* animate */,
@@ -820,6 +826,7 @@
     private void handleQsDown(MotionEvent event) {
         if (event.getActionMasked() == MotionEvent.ACTION_DOWN
                 && shouldQuickSettingsIntercept(event.getX(), event.getY(), -1)) {
+            mLockedPhoneAnalytics.onQsDown();
             mQsTracking = true;
             onQsExpansionStarted();
             mInitialHeightOnTouch = mQsExpansionHeight;
@@ -987,6 +994,7 @@
             mQsExpanded = expanded;
             updateQsState();
             requestPanelHeightUpdate();
+            mLockedPhoneAnalytics.setQsExpanded(expanded);
             mNotificationStackScroller.setInterceptDelegateEnabled(expanded);
             mStatusBar.setQsExpanded(expanded);
             mQsPanel.setExpanded(expanded);
@@ -1313,6 +1321,10 @@
                     R.string.accessibility_desc_quick_settings));
             mLastAnnouncementWasQuickSettings = true;
         }
+        if (mQsFullyExpanded && mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+            mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
+                    false /* dismissShade */, true /* afterKeyguardGone */);
+        }
         if (DEBUG) {
             invalidate();
         }
@@ -1840,6 +1852,7 @@
 
     @Override
     protected void onTrackingStarted() {
+        mLockedPhoneAnalytics.onTrackingStarted();
         super.onTrackingStarted();
         if (mQsFullyExpanded) {
             mQsExpandImmediate = true;
@@ -1853,6 +1866,7 @@
 
     @Override
     protected void onTrackingStopped(boolean expand) {
+        mLockedPhoneAnalytics.onTrackingStopped();
         super.onTrackingStopped(expand);
         if (expand) {
             mNotificationStackScroller.setOverScrolledPixels(
@@ -1951,11 +1965,35 @@
         if (start) {
             EventLogTags.writeSysuiLockscreenGesture(
                     EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER, lengthDp, velocityDp);
-            mKeyguardBottomArea.launchLeftAffordance();
+
+            mLockedPhoneAnalytics.onLeftAffordanceOn();
+            if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+                mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
+                    @Override
+                    public void run() {
+                        mKeyguardBottomArea.launchLeftAffordance();
+                    }
+                }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+            }
+            else {
+                mKeyguardBottomArea.launchLeftAffordance();
+            }
         } else {
             EventLogTags.writeSysuiLockscreenGesture(
                     EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
-            mSecureCameraLaunchManager.startSecureCameraLaunch();
+
+            mLockedPhoneAnalytics.onCameraOn();
+            if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+                mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
+                    @Override
+                    public void run() {
+                        mSecureCameraLaunchManager.startSecureCameraLaunch();
+                    }
+                }, null, true /* dismissShade */, false /* afterKeyguardGone */);
+            }
+            else {
+                mSecureCameraLaunchManager.startSecureCameraLaunch();
+            }
         }
         mStatusBar.startLaunchTransitionTimeout();
         mBlockTouches = true;
@@ -1999,6 +2037,7 @@
 
     @Override
     public void onSwipingStarted(boolean rightIcon) {
+        mLockedPhoneAnalytics.onAffordanceSwipingStarted(rightIcon);
         boolean camera = getLayoutDirection() == LAYOUT_DIRECTION_RTL ? !rightIcon
                 : rightIcon;
         if (camera) {
@@ -2012,6 +2051,7 @@
 
     @Override
     public void onSwipingAborted() {
+        mLockedPhoneAnalytics.onAffordanceSwipingAborted();
         mKeyguardBottomArea.unbindCameraPrewarmService(false /* launched */);
     }
 
@@ -2393,4 +2433,36 @@
     public boolean hasOverlappingRendering() {
         return !mDozing;
     }
+
+    public void launchCamera(boolean animate) {
+        // If we are launching it when we are occluded already we don't want it to animate,
+        // nor setting these flags, since the occluded state doesn't change anymore, hence it's
+        // never reset.
+        if (!isFullyCollapsed()) {
+            mLaunchingAffordance = true;
+            setLaunchingAffordance(true);
+        } else {
+            animate = false;
+        }
+        mAfforanceHelper.launchAffordance(animate, getLayoutDirection() == LAYOUT_DIRECTION_RTL);
+    }
+
+    public void onAffordanceLaunchEnded() {
+        mLaunchingAffordance = false;
+        setLaunchingAffordance(false);
+    }
+
+    /**
+     * Set whether we are currently launching an affordance. This is currently only set when
+     * launched via a camera gesture.
+     */
+    private void setLaunchingAffordance(boolean launchingAffordance) {
+        getLeftIcon().setLaunchingAffordance(launchingAffordance);
+        getRightIcon().setLaunchingAffordance(launchingAffordance);
+        getCenterIcon().setLaunchingAffordance(launchingAffordance);
+    }
+
+    public boolean canCameraGestureBeLaunched() {
+        return !mAfforanceHelper.isSwipingInProgress();
+    }
 }
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 d8f5ccf..7b04da0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -66,6 +66,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.RankingMap;
@@ -130,6 +131,7 @@
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
 import com.android.systemui.statusbar.policy.AccessibilityController;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -484,6 +486,9 @@
     private Runnable mLaunchTransitionEndRunnable;
     private boolean mLaunchTransitionFadingAway;
     private ExpandableNotificationRow mDraggedDownRow;
+    private boolean mLaunchCameraOnScreenTurningOn;
+    private PowerManager.WakeLock mGestureWakeLock;
+    private Vibrator mVibrator;
 
     // Fingerprint (as computed by getLoggingFingerprint() of the last logged state.
     private int mLastLoggedStateFingerprint;
@@ -589,6 +594,7 @@
     private HashSet<Entry> mHeadsUpEntriesToRemoveOnSwitch = new HashSet<>();
     private RankingMap mLatestRankingMap;
     private boolean mNoAnimationOnNextBarModeChange;
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     @Override
     public void start() {
@@ -636,6 +642,7 @@
         notifyUserAboutHiddenNotifications();
 
         mScreenPinningRequest = new ScreenPinningRequest(mContext);
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(mContext);
     }
 
     // ================================================================================
@@ -916,7 +923,9 @@
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastReceiver.onReceive(mContext,
                 new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
-
+        mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+                "GestureWakeLock");
+        mVibrator = mContext.getSystemService(Vibrator.class);
 
         // receive broadcasts
         IntentFilter filter = new IntentFilter();
@@ -1721,7 +1730,9 @@
 
         final boolean hasArtwork = artworkBitmap != null;
 
-        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE) {
+        if ((hasArtwork || DEBUG_MEDIA_FAKE_ARTWORK) && mState != StatusBarState.SHADE
+                && mFingerprintUnlockController.getMode()
+                        != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
             // time to show some art!
             if (mBackdrop.getVisibility() != View.VISIBLE) {
                 mBackdrop.setVisibility(View.VISIBLE);
@@ -1776,31 +1787,40 @@
                 if (DEBUG_MEDIA) {
                     Log.v(TAG, "DEBUG_MEDIA: Fading out album artwork");
                 }
-                mBackdrop.animate()
-                        // Never let the alpha become zero - otherwise the RenderNode
-                        // won't draw anything and uninitialized memory will show through
-                        // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in libhwui.
-                        .alpha(0.002f)
-                        .setInterpolator(mBackdropInterpolator)
-                        .setDuration(300)
-                        .setStartDelay(0)
-                        .withEndAction(new Runnable() {
-                            @Override
-                            public void run() {
-                                mBackdrop.setVisibility(View.GONE);
-                                mBackdropFront.animate().cancel();
-                                mBackdropBack.animate().cancel();
-                                mHandler.post(mHideBackdropFront);
-                            }
-                        });
-                if (mKeyguardFadingAway) {
-                    mBackdrop.animate()
+                if (mFingerprintUnlockController.getMode()
+                        == FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING) {
 
-                            // Make it disappear faster, as the focus should be on the activity behind.
-                            .setDuration(mKeyguardFadingAwayDuration / 2)
-                            .setStartDelay(mKeyguardFadingAwayDelay)
-                            .setInterpolator(mLinearInterpolator)
-                            .start();
+                    // We are unlocking directly - no animation!
+                    mBackdrop.setVisibility(View.GONE);
+                } else {
+                    mBackdrop.animate()
+                            // Never let the alpha become zero - otherwise the RenderNode
+                            // won't draw anything and uninitialized memory will show through
+                            // if mScrimSrcModeEnabled. Note that 0.001 is rounded down to 0 in
+                            // libhwui.
+                            .alpha(0.002f)
+                            .setInterpolator(mBackdropInterpolator)
+                            .setDuration(300)
+                            .setStartDelay(0)
+                            .withEndAction(new Runnable() {
+                                @Override
+                                public void run() {
+                                    mBackdrop.setVisibility(View.GONE);
+                                    mBackdropFront.animate().cancel();
+                                    mBackdropBack.animate().cancel();
+                                    mHandler.post(mHideBackdropFront);
+                                }
+                            });
+                    if (mKeyguardFadingAway) {
+                        mBackdrop.animate()
+
+                                // Make it disappear faster, as the focus should be on the activity
+                                // behind.
+                                .setDuration(mKeyguardFadingAwayDuration / 2)
+                                .setStartDelay(mKeyguardFadingAwayDelay)
+                                .setInterpolator(mLinearInterpolator)
+                                .start();
+                    }
                 }
             }
         }
@@ -2462,8 +2482,12 @@
                         || mStatusBarMode == MODE_LIGHTS_OUT_TRANSPARENT);
                 boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
                 boolean light = (vis & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR) != 0;
-
-                mIconController.setIconsDark(allowLight && light);
+                boolean animate = mFingerprintUnlockController == null
+                        || (mFingerprintUnlockController.getMode()
+                                != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
+                        && mFingerprintUnlockController.getMode()
+                                != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+                mIconController.setIconsDark(allowLight && light, animate);
             }
             // restore the recents bit
             if (wasRecentsVisible) {
@@ -3407,6 +3431,8 @@
 
     private void onLaunchTransitionFadingEnded() {
         mNotificationPanel.setAlpha(1.0f);
+        mNotificationPanel.onAffordanceLaunchEnded();
+        releaseGestureWakeLock();
         runLaunchTransitionEndRunnable();
         mLaunchTransitionFadingAway = false;
         mScrimController.forceHideScrims(false /* hide */);
@@ -3478,7 +3504,8 @@
                 .alpha(0f)
                 .setStartDelay(0)
                 .setDuration(FADE_KEYGUARD_DURATION_PULSING)
-                .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR);
+                .setInterpolator(ScrimController.KEYGUARD_FADE_OUT_INTERPOLATOR)
+                .start();
     }
 
     /**
@@ -3493,6 +3520,8 @@
 
     private void onLaunchTransitionTimeout() {
         Log.w(TAG, "Launch transition: Timeout!");
+        mNotificationPanel.onAffordanceLaunchEnded();
+        releaseGestureWakeLock();
         mNotificationPanel.resetViews();
     }
 
@@ -3544,10 +3573,18 @@
             mQSPanel.refreshAllTiles();
         }
         mHandler.removeMessages(MSG_LAUNCH_TRANSITION_TIMEOUT);
+        releaseGestureWakeLock();
+        mNotificationPanel.onAffordanceLaunchEnded();
         mNotificationPanel.setAlpha(1f);
         return staying;
     }
 
+    private void releaseGestureWakeLock() {
+        if (mGestureWakeLock.isHeld()) {
+            mGestureWakeLock.release();
+        }
+    }
+
     public long calculateGoingToFullShadeDelay() {
         return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
     }
@@ -3685,6 +3722,11 @@
         return mState == StatusBarState.KEYGUARD && mStatusBarKeyguardViewManager.onMenuPressed();
     }
 
+    public void endAffordanceLaunch() {
+        releaseGestureWakeLock();
+        mNotificationPanel.onAffordanceLaunchEnded();
+    }
+
     public boolean onBackPressed() {
         if (mStatusBarKeyguardViewManager.onBackPressed()) {
             return true;
@@ -3761,6 +3803,7 @@
         }
         mState = state;
         mGroupManager.setStatusBarState(state);
+        mLockedPhoneAnalytics.setStatusBarState(state);
         mStatusBarWindowManager.setStatusBarState(state);
         updateDozing();
     }
@@ -3782,6 +3825,7 @@
     }
 
     public void onUnlockHintStarted() {
+        mLockedPhoneAnalytics.onUnlockHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock);
     }
 
@@ -3791,14 +3835,17 @@
     }
 
     public void onCameraHintStarted() {
+        mLockedPhoneAnalytics.onCameraHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.camera_hint);
     }
 
     public void onVoiceAssistHintStarted() {
+        mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.voice_hint);
     }
 
     public void onPhoneHintStarted() {
+        mLockedPhoneAnalytics.onLeftAffordanceHintStarted();
         mKeyguardIndicationController.showTransientIndication(R.string.phone_hint);
     }
 
@@ -3873,7 +3920,7 @@
             row.setUserExpanded(true);
         }
         boolean fullShadeNeedsBouncer = !userAllowsPrivateNotificationsInPublic(mCurrentUserId)
-                || !mShowLockscreenNotifications;
+                || !mShowLockscreenNotifications || mLockedPhoneAnalytics.shouldEnforceBouncer();
         if (isLockscreenPublicMode() && fullShadeNeedsBouncer) {
             mLeaveOpenOnKeyguardHide = true;
             showBouncer();
@@ -3915,9 +3962,13 @@
     }
 
     public void onFinishedGoingToSleep() {
+        mNotificationPanel.onAffordanceLaunchEnded();
+        releaseGestureWakeLock();
+        mLaunchCameraOnScreenTurningOn = false;
         mDeviceInteractive = false;
         mWakeUpComingFromTouch = false;
         mWakeUpTouchLocation = null;
+        mLockedPhoneAnalytics.onScreenOff();
         mStackScroller.setAnimationsEnabled(false);
         updateVisibleToUser();
     }
@@ -3927,10 +3978,19 @@
         mStackScroller.setAnimationsEnabled(true);
         mNotificationPanel.setTouchDisabled(false);
         updateVisibleToUser();
+        mLockedPhoneAnalytics.onScreenOn();
     }
 
     public void onScreenTurningOn() {
         mNotificationPanel.onScreenTurningOn();
+        if (mLaunchCameraOnScreenTurningOn) {
+            mNotificationPanel.launchCamera(false);
+            mLaunchCameraOnScreenTurningOn = false;
+        }
+    }
+
+    private void vibrateForCameraGesture() {
+        mVibrator.vibrate(1000L);
     }
 
     public void onScreenTurnedOn() {
@@ -4055,6 +4115,7 @@
             mWakeUpTouchLocation = new PointF(event.getX(), event.getY());
             mNotificationPanel.setTouchDisabled(false);
             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+            mLockedPhoneAnalytics.onScreenOnFromTouch();
         }
     }
 
@@ -4077,8 +4138,9 @@
     public void appTransitionStarting(long startTime, long duration) {
 
         // Use own timings when Keyguard is going away, see keyguardGoingAway and
-        // setKeyguardFadingAway
-        if (!mKeyguardFadingAway) {
+        // setKeyguardFadingAway. When duration is 0, skip this one because no animation is really
+        // playing.
+        if (!mKeyguardFadingAway && duration > 0) {
             mIconController.appTransitionStarting(startTime, duration);
         }
         if (mIconPolicy != null) {
@@ -4086,6 +4148,39 @@
         }
     }
 
+    @Override
+    public void onCameraLaunchGestureDetected() {
+        if (!mNotificationPanel.canCameraGestureBeLaunched()) {
+            return;
+        }
+        if (!mDeviceInteractive) {
+            PowerManager pm = mContext.getSystemService(PowerManager.class);
+            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
+            mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
+        }
+        vibrateForCameraGesture();
+        if (!mStatusBarKeyguardViewManager.isShowing()) {
+            startActivity(KeyguardBottomAreaView.INSECURE_CAMERA_INTENT,
+                    true /* dismissShade */);
+        } else {
+            if (!mDeviceInteractive) {
+                // Avoid flickering of the scrim when we instant launch the camera and the bouncer
+                // comes on.
+                mScrimController.dontAnimateBouncerChangesUntilNextFrame();
+                mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
+            }
+            if (mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
+                mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
+            } else {
+                // We need to defer the camera launch until the screen comes on, since otherwise
+                // we will dismiss us too early since we are waiting on an activity to be drawn and
+                // incorrectly get notified because of the screen on event (which resumes and pauses
+                // some activities)
+                mLaunchCameraOnScreenTurningOn = true;
+            }
+        }
+    }
+
     public void notifyFpAuthModeChanged() {
         updateDozing();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 5b009ee..b9e9292 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -22,7 +22,6 @@
 import android.animation.ValueAnimator;
 import android.content.Context;
 import android.graphics.Color;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewTreeObserver;
 import android.view.animation.DecelerateInterpolator;
@@ -87,6 +86,8 @@
     private float mTopHeadsUpDragAmount;
     private View mDraggedHeadsUpView;
     private boolean mForceHideScrims;
+    private boolean mSkipFirstFrame;
+    private boolean mDontAnimateBouncerChanges;
 
     public ScrimController(ScrimView scrimBehind, ScrimView scrimInFront, View headsUpScrim,
             boolean scrimSrcEnabled) {
@@ -125,7 +126,7 @@
 
     public void setBouncerShowing(boolean showing) {
         mBouncerShowing = showing;
-        mAnimateChange = !mExpanding;
+        mAnimateChange = !mExpanding && !mDontAnimateBouncerChanges;
         scheduleUpdate();
     }
 
@@ -134,14 +135,20 @@
         scheduleUpdate();
     }
 
-    public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished) {
+    public void animateKeyguardFadingOut(long delay, long duration, Runnable onAnimationFinished,
+            boolean skipFirstFrame) {
         mWakeAndUnlocking = false;
         mAnimateKeyguardFadingOut = true;
         mDurationOverride = duration;
         mAnimationDelay = delay;
         mAnimateChange = true;
+        mSkipFirstFrame = skipFirstFrame;
         mOnAnimationFinished = onAnimationFinished;
         scheduleUpdate();
+
+        // No need to wait for the next frame to be drawn for this case - onPreDraw will execute
+        // the changes we just scheduled.
+        onPreDraw();
     }
 
     public void abortKeyguardFadingOut() {
@@ -339,6 +346,9 @@
             }
         });
         anim.start();
+        if (mSkipFirstFrame) {
+            anim.setCurrentPlayTime(16);
+        }
         scrim.setTag(TAG_KEY_ANIM, anim);
         scrim.setTag(TAG_KEY_ANIM_TARGET, target);
     }
@@ -351,9 +361,13 @@
     public boolean onPreDraw() {
         mScrimBehind.getViewTreeObserver().removeOnPreDrawListener(this);
         mUpdatePending = false;
+        if (mDontAnimateBouncerChanges) {
+            mDontAnimateBouncerChanges = false;
+        }
         updateScrims();
         mDurationOverride = -1;
         mAnimationDelay = 0;
+        mSkipFirstFrame = false;
 
         // Make sure that we always call the listener even if we didn't start an animation.
         endAnimateKeyguardFadingOut(false /* force */);
@@ -486,4 +500,8 @@
         mAnimateChange = false;
         scheduleUpdate();
     }
+
+    public void dontAnimateBouncerChangesUntilNextFrame() {
+        mDontAnimateBouncerChanges = true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
index a1e9ece..18db5b8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -19,6 +19,7 @@
 import android.animation.Animator.AnimatorListener;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.graphics.drawable.RippleDrawable;
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index 7ee47df..e9c4e49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -26,6 +26,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Drawable;
+import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
 import android.util.MathUtils;
 import android.util.TypedValue;
@@ -184,6 +185,12 @@
             }
         });
         requestCaptureValues();
+
+        // RenderThread is doing more harm than good when touching the header (to expand quick
+        // settings), so disable it for this view
+        ((RippleDrawable) getBackground()).setForceSoftware(true);
+        ((RippleDrawable) mSettingsButton.getBackground()).setForceSoftware(true);
+        ((RippleDrawable) mSystemIconsSuperContainer.getBackground()).setForceSoftware(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
index 067e50e..5de1c13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java
@@ -335,8 +335,10 @@
         }
     }
 
-    public void setIconsDark(boolean dark) {
-        if (mTransitionPending) {
+    public void setIconsDark(boolean dark, boolean animate) {
+        if (!animate) {
+            setIconTintInternal(dark ? 1.0f : 0.0f);
+        } else if (mTransitionPending) {
             deferIconTintChange(dark ? 1.0f : 0.0f);
         } else if (mTransitionDeferring) {
             animateIconTint(dark ? 1.0f : 0.0f,
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 7e83f26..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;
@@ -74,7 +75,6 @@
     private boolean mLastOccluded;
     private boolean mLastBouncerShowing;
     private boolean mLastBouncerDismissible;
-    private boolean mLastDeferScrimFadeOut;
     private OnDismissAction mAfterKeyguardGoneAction;
     private boolean mDeviceWillWakeUp;
     private boolean mDeferScrimFadeOut;
@@ -180,11 +180,16 @@
         mPhoneStatusBar.onScreenTurningOn();
     }
 
+    public boolean isScreenTurnedOn() {
+        return mScreenTurnedOn;
+    }
+
     public void onScreenTurnedOn() {
         mScreenTurnedOn = true;
         if (mDeferScrimFadeOut) {
             mDeferScrimFadeOut = false;
-            animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS);
+            animateScrimControllerKeyguardFadingOut(0, WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
+                    true /* skipFirstFrame */);
             updateStates();
         }
         mPhoneStatusBar.onScreenTurnedOn();
@@ -264,7 +269,8 @@
                     updateStates();
                     mScrimController.animateKeyguardFadingOut(
                             PhoneStatusBar.FADE_KEYGUARD_START_DELAY,
-                            PhoneStatusBar.FADE_KEYGUARD_DURATION, null);
+                            PhoneStatusBar.FADE_KEYGUARD_DURATION, null,
+                            false /* skipFirstFrame */);
                 }
             }, new Runnable() {
                 @Override
@@ -287,7 +293,7 @@
                     public void run() {
                         mPhoneStatusBar.hideKeyguard();
                     }
-                });
+                }, false /* skipFirstFrame */);
             } else {
                 mFingerprintUnlockController.startKeyguardFadingAway();
                 mPhoneStatusBar.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
@@ -302,10 +308,12 @@
 
                             // Screen is already on, don't defer with fading out.
                             animateScrimControllerKeyguardFadingOut(0,
-                                    WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS);
+                                    WAKE_AND_UNLOCK_SCRIM_FADEOUT_DURATION_MS,
+                                    true /* skipFirstFrame */);
                         }
                     } else {
-                        animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration);
+                        animateScrimControllerKeyguardFadingOut(delay, fadeoutDuration,
+                                false /* skipFirstFrame */);
                     }
                 } else {
                     mScrimController.animateGoingToFullShade(delay, fadeoutDuration);
@@ -320,12 +328,14 @@
         }
     }
 
-    private void animateScrimControllerKeyguardFadingOut(long delay, long duration) {
-        animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */);
+    private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
+            boolean skipFirstFrame) {
+        animateScrimControllerKeyguardFadingOut(delay, duration, null /* endRunnable */,
+                skipFirstFrame);
     }
 
     private void animateScrimControllerKeyguardFadingOut(long delay, long duration,
-            final Runnable endRunnable) {
+            final Runnable endRunnable, boolean skipFirstFrame) {
         Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, "Fading out", 0);
         mScrimController.animateKeyguardFadingOut(delay, duration, new Runnable() {
             @Override
@@ -340,7 +350,7 @@
                         ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN);
                 Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, "Fading out", 0);
             }
-        });
+        }, skipFirstFrame);
     }
 
     private void executeAfterKeyguardGoneAction() {
@@ -380,6 +390,7 @@
      */
     public boolean onBackPressed() {
         if (mBouncer.isShowing()) {
+            mPhoneStatusBar.endAffordanceLaunch();
             reset();
             return true;
         }
@@ -414,7 +425,6 @@
         boolean occluded = mOccluded;
         boolean bouncerShowing = mBouncer.isShowing();
         boolean bouncerDismissible = !mBouncer.isFullscreenBouncer();
-        boolean deferScrimFadeOut = mDeferScrimFadeOut;
 
         if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing)
                 || mFirstUpdate) {
@@ -425,11 +435,8 @@
             }
         }
 
-        // Hide navigation bar on Keyguard but not on bouncer and also if we are deferring a scrim
-        // fade out, i.e. we are waiting for the screen to have turned on.
-        boolean navBarVisible = !deferScrimFadeOut && (!(showing && !occluded) || bouncerShowing);
-        boolean lastNavBarVisible = !mLastDeferScrimFadeOut && (!(mLastShowing && !mLastOccluded)
-                || mLastBouncerShowing);
+        boolean navBarVisible = (!(showing && !occluded) || bouncerShowing);
+        boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing);
         if (navBarVisible != lastNavBarVisible || mFirstUpdate) {
             if (mPhoneStatusBar.getNavigationBarView() != null) {
                 if (navBarVisible) {
@@ -464,7 +471,6 @@
         mFirstUpdate = false;
         mLastShowing = showing;
         mLastOccluded = occluded;
-        mLastDeferScrimFadeOut = deferScrimFadeOut;
         mLastBouncerShowing = bouncerShowing;
         mLastBouncerDismissible = bouncerDismissible;
 
@@ -528,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/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 0e22aa8..bbf981f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -39,6 +39,7 @@
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 
@@ -55,12 +56,14 @@
 
     private PhoneStatusBar mService;
     private final Paint mTransparentSrcPaint = new Paint();
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
         setMotionEventSplittingEnabled(false);
         mTransparentSrcPaint.setColor(0);
         mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     @Override
@@ -197,6 +200,7 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
+        mLockedPhoneAnalytics.onTouchEvent(ev, getWidth(), getHeight());
         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
             // Disallow new pointers while the brightness mirror is visible. This is so that you
             // can't touch anything other than the brightness slider while the mirror is showing
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
index 091db76..a91cd51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockMethodCache.java
@@ -145,7 +145,7 @@
         }
 
         @Override
-        public void onStrongAuthTimeoutExpiredChanged(int userId) {
+        public void onStrongAuthStateChanged(int userId) {
             update(false /* updateAlways */);
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
new file mode 100644
index 0000000..afc8f77
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/touch_analytics.proto
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+syntax = "proto2";
+
+package systemui;
+
+option java_package = "com.android.systemui.statusbar.phone";
+option java_outer_classname = "TouchAnalyticsProto";
+
+message Session {
+    message TouchEvent {
+        message BoundingBox {
+            optional float width = 1;
+            optional float height = 2;
+        }
+
+        enum Action {
+            // Keep in sync with MotionEvent.
+            DOWN = 0;
+            UP = 1;
+            MOVE = 2;
+            CANCEL = 3;
+            OUTSIDE = 4;
+            POINTER_DOWN = 5;
+            POINTER_UP = 6;
+        }
+
+        message Pointer {
+            optional float x = 1;
+            optional float y = 2;
+            optional float size = 3;
+            optional float pressure = 4;
+            optional int32 id = 5;
+            optional float removed_length = 6;
+            optional BoundingBox removed_boundingBox = 7;
+        }
+
+        optional uint64 timeOffsetNanos = 1;
+        optional Action action = 2;
+        optional int32 actionIndex = 3;
+        repeated Pointer pointers = 4;
+        optional bool removed_redacted = 5;
+        optional BoundingBox removed_boundingBox = 6;
+    }
+
+    message SensorEvent {
+        enum Type {
+            ACCELEROMETER = 1;
+            GYROSCOPE = 4;
+            LIGHT = 5;
+            PROXIMITY = 8;
+            ROTATION_VECTOR = 11;
+        }
+
+        optional Type type = 1;
+        optional uint64 timeOffsetNanos = 2;
+        repeated float values = 3;
+        optional uint64 timestamp = 4;
+    }
+
+    message PhoneEvent {
+        enum Type {
+            ON_SCREEN_ON = 0;
+            ON_SCREEN_ON_FROM_TOUCH = 1;
+            ON_SCREEN_OFF = 2;
+            ON_SUCCESSFUL_UNLOCK = 3;
+            ON_BOUNCER_SHOWN = 4;
+            ON_BOUNCER_HIDDEN = 5;
+            ON_QS_DOWN = 6;
+            SET_QS_EXPANDED_TRUE = 7;
+            SET_QS_EXPANDED_FALSE = 8;
+            ON_TRACKING_STARTED = 9;
+            ON_TRACKING_STOPPED = 10;
+            ON_NOTIFICATION_ACTIVE = 11;
+            ON_NOTIFICATION_INACTIVE = 12;
+            ON_NOTIFICATION_DOUBLE_TAP = 13;
+            SET_NOTIFICATION_EXPANDED = 14;
+            RESET_NOTIFICATION_EXPANDED = 15;
+            ON_NOTIFICATION_START_DRAGGING_DOWN = 16;
+            ON_NOTIFICATION_STOP_DRAGGING_DOWN = 17;
+            ON_NOTIFICATION_DISMISSED = 18;
+            ON_NOTIFICATION_START_DISMISSING = 19;
+            ON_NOTIFICATION_STOP_DISMISSING = 20;
+            ON_RIGHT_AFFORDANCE_SWIPING_STARTED = 21;
+            ON_LEFT_AFFORDANCE_SWIPING_STARTED = 22;
+            ON_AFFORDANCE_SWIPING_ABORTED = 23;
+            ON_CAMERA_ON = 24;
+            ON_LEFT_AFFORDANCE_ON = 25;
+            ON_UNLOCK_HINT_STARTED = 26;
+            ON_CAMERA_HINT_STARTED = 27;
+            ON_LEFT_AFFORDANCE_HINT_STARTED = 28;
+        }
+
+        optional Type type = 1;
+        optional uint64 timeOffsetNanos = 2;
+    }
+
+    enum Result {
+        FAILURE = 0;
+        SUCCESS = 1;
+        UNKNOWN = 2;
+    }
+
+    enum Type {
+        RESERVED_1 = 0;
+        RESERVED_2 = 1;
+        RANDOM_WAKEUP = 2;
+        REAL = 3;
+    }
+
+    optional uint64 startTimestampMillis = 1;
+    optional uint64 durationMillis = 2;
+    optional string build = 3;
+    optional Result result = 4;
+    repeated TouchEvent touchEvents = 5;
+    repeated SensorEvent sensorEvents = 6;
+
+    optional int32 touchAreaWidth = 9;
+    optional int32 touchAreaHeight = 10;
+    optional Type type = 11;
+    repeated PhoneEvent phoneEvents = 12;
+}
\ No newline at end of file
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 6af9854..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
@@ -178,7 +184,8 @@
         mCurrentUserId = newUserId;
         if (mUserManager.getUserInfo(newUserId).isRestricted()) {
             // VPN for a restricted profile is routed through its owner user
-            mVpnUserId = UserHandle.USER_OWNER;
+            // TODO: http://b/22950929
+            mVpnUserId = UserHandle.USER_SYSTEM;
         } else {
             mVpnUserId = mCurrentUserId;
         }
@@ -202,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/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 753a7f7..56f6564 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -34,6 +34,7 @@
     boolean hasDelays;
     boolean hasGoToFullShadeEvent;
     boolean hasDarkEvent;
+    boolean hasHeadsUpDisappearClickEvent;
     int darkAnimationOriginIndex;
 
     public AnimationFilter animateAlpha() {
@@ -106,6 +107,10 @@
                 hasDarkEvent = true;
                 darkAnimationOriginIndex = ev.darkAnimationOriginIndex;
             }
+            if (ev.animationType == NotificationStackScrollLayout.AnimationEvent
+                    .ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
+                hasHeadsUpDisappearClickEvent = true;
+            }
         }
     }
 
@@ -135,6 +140,7 @@
         hasDelays = false;
         hasGoToFullShadeEvent = false;
         hasDarkEvent = false;
+        hasHeadsUpDisappearClickEvent = false;
         darkAnimationOriginIndex =
                 NotificationStackScrollLayout.AnimationEvent.DARK_ANIMATION_ORIGIN_INDEX_ABOVE;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 82c1aa8..a1d73d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -47,6 +47,7 @@
 import com.android.systemui.statusbar.SpeedBumpView;
 import com.android.systemui.statusbar.StackScrollerDecorView;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.analytics.LockedPhoneAnalytics;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.phone.ScrimController;
@@ -231,6 +232,7 @@
     private boolean mForceNoOverlappingRendering;
     private NotificationOverflowContainer mOverflowContainer;
     private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
+    private LockedPhoneAnalytics mLockedPhoneAnalytics;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -264,6 +266,7 @@
             mDebugPaint.setStrokeWidth(2);
             mDebugPaint.setStyle(Paint.Style.STROKE);
         }
+        mLockedPhoneAnalytics = LockedPhoneAnalytics.getInstance(context);
     }
 
     @Override
@@ -595,6 +598,12 @@
             veto.performClick();
         }
         if (DEBUG) Log.v(TAG, "onChildDismissed: " + v);
+
+        mLockedPhoneAnalytics.onNotificationDismissed();
+        if (mLockedPhoneAnalytics.shouldEnforceBouncer()) {
+            mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
+                    false /* dismissShade */, true /* afterKeyguardGone */);
+        }
     }
 
     @Override
@@ -622,6 +631,7 @@
     }
 
     public void onBeginDrag(View v) {
+        mLockedPhoneAnalytics.onNotificatonStartDismissing();
         setSwipingInProgress(true);
         mAmbientState.onBeginDrag(v);
         if (mAnimationsEnabled && (mIsExpanded || !isPinnedHeadsUp(v))) {
@@ -648,6 +658,7 @@
     }
 
     public void onDragCancelled(View v) {
+        mLockedPhoneAnalytics.onNotificatonStopDismissing();
         setSwipingInProgress(false);
     }
 
@@ -1915,7 +1926,9 @@
             boolean onBottom = false;
             boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
             if (!mIsExpanded && !isHeadsUp) {
-                type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+                type = row.wasJustClicked()
+                        ? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+                        : AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
             } else {
                 StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
                 if (viewState == null) {
@@ -3016,6 +3029,15 @@
                         .animateY()
                         .animateZ(),
 
+                // ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+                new AnimationFilter()
+                        .animateAlpha()
+                        .animateHeight()
+                        .animateTopInset()
+                        .animateY()
+                        .animateZ()
+                        .hasDelays(),
+
                 // ANIMATION_TYPE_HEADS_UP_OTHER
                 new AnimationFilter()
                         .animateAlpha()
@@ -3087,6 +3109,9 @@
                 // ANIMATION_TYPE_HEADS_UP_DISAPPEAR
                 StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
 
+                // ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+                StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
+
                 // ANIMATION_TYPE_HEADS_UP_OTHER
                 StackStateAnimator.ANIMATION_DURATION_STANDARD,
 
@@ -3110,8 +3135,9 @@
         static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 13;
         static final int ANIMATION_TYPE_HEADS_UP_APPEAR = 14;
         static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR = 15;
-        static final int ANIMATION_TYPE_HEADS_UP_OTHER = 16;
-        static final int ANIMATION_TYPE_EVERYTHING = 17;
+        static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK = 16;
+        static final int ANIMATION_TYPE_HEADS_UP_OTHER = 17;
+        static final int ANIMATION_TYPE_EVERYTHING = 18;
 
         static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
         static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 82064a7..cf696a1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -127,7 +127,7 @@
         mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
                 R.dimen.notification_collapse_second_card_padding);
         mScaleDimmed = context.getResources().getDisplayMetrics().densityDpi
-                >= DisplayMetrics.DENSITY_XXHIGH;
+                >= DisplayMetrics.DENSITY_420;
     }
 
     public boolean shouldScaleDimmed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 97c7d30..b4ab48a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -54,6 +54,7 @@
     public static final int ANIMATION_DELAY_PER_ELEMENT_DARK = 24;
     public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE = 2;
     public static final int DELAY_EFFECT_MAX_INDEX_DIFFERENCE_CHILDREN = 3;
+    public static final int ANIMATION_DELAY_HEADS_UP = 120;
 
     private static final int TAG_ANIMATOR_TRANSLATION_Y = R.id.translation_y_animator_tag;
     private static final int TAG_ANIMATOR_TRANSLATION_Z = R.id.translation_z_animator_tag;
@@ -320,6 +321,9 @@
         if (mAnimationFilter.hasGoToFullShadeEvent) {
             return calculateDelayGoToFullShade(viewState);
         }
+        if (mAnimationFilter.hasHeadsUpDisappearClickEvent) {
+            return ANIMATION_DELAY_HEADS_UP;
+        }
         long minDelay = 0;
         for (NotificationStackScrollLayout.AnimationEvent event : mNewEvents) {
             long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING;
@@ -890,7 +894,9 @@
                 mHeadsUpAppearChildren.add(changingView);
                 finalState.applyState(changingView, mTmpState);
             } else if (event.animationType == NotificationStackScrollLayout
-                    .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
+                            .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR ||
+                    event.animationType == NotificationStackScrollLayout
+                            .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK) {
                 mHeadsUpDisappearChildren.add(changingView);
                 if (mHostLayout.indexOfChild(changingView) == -1) {
                     // This notification was actually removed, so we need to add it to the overlay
@@ -900,7 +906,11 @@
                     // We temporarily enable Y animations, the real filter will be combined
                     // afterwards anyway
                     mAnimationFilter.animateY = true;
-                    startViewAnimations(changingView, mTmpState, 0,
+                    startViewAnimations(changingView, mTmpState,
+                            event.animationType == NotificationStackScrollLayout
+                                    .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
+                                            ? ANIMATION_DELAY_HEADS_UP
+                                            : 0,
                             ANIMATION_DURATION_HEADS_UP_DISAPPEAR);
                     mChildrenToClearFromOverlay.add(changingView);
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 920b682..2587b9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -171,6 +171,10 @@
     }
 
     @Override
+    public void onCameraLaunchGestureDetected() {
+    }
+
+    @Override
     protected void updateHeadsUp(String key, NotificationData.Entry entry, boolean shouldInterrupt,
             boolean alertAgain) {
     }
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 6a7201c..d6d17cb 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -17,9 +17,14 @@
 
 LOCAL_MODULE_TAGS := tests
 
+LOCAL_PROTOC_OPTIMIZE_TYPE := nano
+LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
+LOCAL_PROTO_JAVA_OUTPUT_PARAMS := optional_field_style=accessors
+
 LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages com.android.systemui:com.android.keyguard
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-java-files-under, ../src) \
+    $(call all-proto-files-under, ../src) \
     src/com/android/systemui/EventLogTags.logtags
 
 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res \
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 4d0e28b..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
@@ -72,7 +72,7 @@
         mMockEdit = mock(SharedPreferences.Editor.class);
         mMockUserManager = mock(UserManager.class);
 
-        when (context.getSharedPreferences(
+        when(context.getSharedPreferences(
                 "com.android.systemui.navbarapps", Context.MODE_PRIVATE)).thenReturn(mMockPrefs);
         when(context.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
         when(context.getPackageManager()).thenReturn(mMockPackageManager);
@@ -84,9 +84,22 @@
         when(mMockPrefs.getInt("version", -1)).thenReturn(3);
         when(mMockPrefs.edit()).thenReturn(mMockEdit);
 
-        when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(22L);
-        when(mMockUserManager.getUserForSerialNumber(45L)).thenReturn(new UserHandle(4));
-        when(mMockUserManager.getUserForSerialNumber(239L)).thenReturn(new UserHandle(5));
+        when(mMockUserManager.getSerialNumberForUser(new UserHandle(2))).thenReturn(222L);
+        when(mMockUserManager.getSerialNumberForUser(new UserHandle(4))).thenReturn(444L);
+        when(mMockUserManager.getSerialNumberForUser(new UserHandle(5))).thenReturn(555L);
+        when(mMockUserManager.getUserForSerialNumber(222L)).thenReturn(new UserHandle(2));
+        when(mMockUserManager.getUserForSerialNumber(444L)).thenReturn(new UserHandle(4));
+        when(mMockUserManager.getUserForSerialNumber(555L)).thenReturn(new UserHandle(5));
+
+        UserInfo ui2 = new UserInfo();
+        ui2.profileGroupId = 999;
+        UserInfo ui4 = new UserInfo();
+        ui4.profileGroupId = 999;
+        UserInfo ui5 = new UserInfo();
+        ui5.profileGroupId = 999;
+        when(mMockUserManager.getUserInfo(2)).thenReturn(ui2);
+        when(mMockUserManager.getUserInfo(4)).thenReturn(ui4);
+        when(mMockUserManager.getUserInfo(5)).thenReturn(ui5);
 
         mModel = new NavigationBarAppsModel(context) {
             @Override
@@ -134,19 +147,24 @@
                 .queryIntentActivitiesAsUser(any(Intent.class), eq(0), any(int.class)))
                 .thenReturn(Arrays.asList(ri0, ri1));
 
+        mModel.setCurrentUser(3);
         // Unlauncheable (for various reasons) apps.
         assertEquals(null, mModel.buildAppLaunchIntent(
-                new ComponentName("package0", "class0"), new UserHandle(3)));
+                new AppInfo(new ComponentName("package0", "class0"), new UserHandle(3))));
+        mModel.setCurrentUser(4);
         assertEquals(null, mModel.buildAppLaunchIntent(
-                new ComponentName("package1", "class1"), new UserHandle(4)));
+                new AppInfo(new ComponentName("package1", "class1"), new UserHandle(4))));
+        mModel.setCurrentUser(5);
         assertEquals(null, mModel.buildAppLaunchIntent(
-                new ComponentName("package2", "class2"), new UserHandle(5)));
+                new AppInfo(new ComponentName("package2", "class2"), new UserHandle(5))));
+        mModel.setCurrentUser(6);
         assertEquals(null, mModel.buildAppLaunchIntent(
-                new ComponentName("package3", "class3"), new UserHandle(6)));
+                new AppInfo(new ComponentName("package3", "class3"), new UserHandle(6))));
 
         // A launcheable app.
+        mModel.setCurrentUser(7);
         Intent intent = mModel.buildAppLaunchIntent(
-                new ComponentName("package4", "class4"), new UserHandle(7));
+                new AppInfo(new ComponentName("package4", "class4"), new UserHandle(7)));
         assertNotNull(intent);
         assertEquals(new ComponentName("package4", "class4"), intent.getComponent());
         assertEquals("package4", intent.getPackage());
@@ -155,13 +173,11 @@
     /** Initializes the model from SharedPreferences for a few app activites. */
     private void initializeModelFromPrefs() {
         // Assume several apps are stored.
-        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(3);
-        when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(-1L);
-        when(mMockPrefs.getString("22|app_1", null)).thenReturn("package1/class1");
-        when(mMockPrefs.getLong("22|app_user_1", -1)).thenReturn(45L);
-        when(mMockPrefs.getString("22|app_2", null)).thenReturn("package2/class2");
-        when(mMockPrefs.getLong("22|app_user_2", -1)).thenReturn(239L);
+        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
+        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package1/class1");
+        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(444L);
+        when(mMockPrefs.getString("222|app_1", null)).thenReturn("package2/class2");
+        when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(555L);
 
         ActivityInfo mockActivityInfo = new ActivityInfo();
         mockActivityInfo.exported = true;
@@ -202,17 +218,18 @@
     /** Tests initializing the model from SharedPreferences. */
     public void testInitializeFromPrefs() {
         initializeModelFromPrefs();
-        assertEquals(2, mModel.getAppCount());
-        assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(45L, mModel.getApp(0).getUserSerialNumber());
-        assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
-        assertEquals(239L, mModel.getApp(1).getUserSerialNumber());
+        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. */
     public void testInitializeDefaultApps() {
         // Assume the user's app count pref isn't available.
-        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(-1);
+        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
 
         // Assume some installed activities.
         ActivityInfo ai1 = new ActivityInfo();
@@ -231,18 +248,19 @@
 
         // Setting the user should load the installed activities.
         mModel.setCurrentUser(2);
-        assertEquals(2, mModel.getAppCount());
-        assertEquals("package1/class1", mModel.getApp(0).getComponentName().flattenToString());
-        assertEquals(22L, mModel.getApp(0).getUserSerialNumber());
-        assertEquals("package2/class2", mModel.getApp(1).getComponentName().flattenToString());
-        assertEquals(22L, mModel.getApp(1).getUserSerialNumber());
+        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("22|app_count", 2);
-        order.verify(mMockEdit).putString("22|app_0", "package1/class1");
-        order.verify(mMockEdit).putLong("22|app_user_0", 22L);
-        order.verify(mMockEdit).putString("22|app_1", "package2/class2");
-        order.verify(mMockEdit).putLong("22|app_user_1", 22L);
+        order.verify(mMockEdit).putInt("222|app_count", 2);
+        order.verify(mMockEdit).putString("222|app_0", "package1/class1");
+        order.verify(mMockEdit).putLong("222|app_user_0", 222L);
+        order.verify(mMockEdit).putString("222|app_1", "package2/class2");
+        order.verify(mMockEdit).putLong("222|app_user_1", 222L);
         order.verify(mMockEdit).apply();
         verifyNoMoreInteractions(mMockEdit);
     }
@@ -250,12 +268,12 @@
     /** Tests initializing the model if one of the prefs is missing. */
     public void testInitializeWithMissingPref() {
         // Assume two apps are nominally stored.
-        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(239L);
+        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
+        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
+        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
 
         // But assume one pref is missing.
-        when(mMockPrefs.getString("22|app_1", null)).thenReturn(null);
+        when(mMockPrefs.getString("222|app_1", null)).thenReturn(null);
 
         ActivityInfo mockActivityInfo = new ActivityInfo();
         mockActivityInfo.exported = true;
@@ -277,20 +295,26 @@
 
         // 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(239L, mModel.getApp(0).getUserSerialNumber());
+        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");
+        order.verify(mMockEdit).putLong("222|app_user_0", 555L);
+        order.verify(mMockEdit).apply();
         verifyNoMoreInteractions(mMockEdit);
     }
 
     /** Tests initializing the model if one of the apps is unlauncheable. */
     public void testInitializeWithUnlauncheableApp() {
         // Assume two apps are nominally stored.
-        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(2);
-        when(mMockPrefs.getString("22|app_0", null)).thenReturn("package0/class0");
-        when(mMockPrefs.getLong("22|app_user_0", -1)).thenReturn(239L);
-        when(mMockPrefs.getString("22|app_1", null)).thenReturn("package1/class1");
-        when(mMockPrefs.getLong("22|app_user_1", -1)).thenReturn(45L);
+        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(2);
+        when(mMockPrefs.getString("222|app_0", null)).thenReturn("package0/class0");
+        when(mMockPrefs.getLong("222|app_user_0", -1)).thenReturn(555L);
+        when(mMockPrefs.getString("222|app_1", null)).thenReturn("package1/class1");
+        when(mMockPrefs.getLong("222|app_user_1", -1)).thenReturn(444L);
 
         ActivityInfo mockActivityInfo = new ActivityInfo();
         mockActivityInfo.exported = true;
@@ -312,15 +336,16 @@
 
         // 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(239L, mModel.getApp(0).getUserSerialNumber());
+        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.
-        verify(mMockEdit).putInt("22|app_count", 1);
-        verify(mMockEdit).putString("22|app_0", "package0/class0");
-        verify(mMockEdit).putLong("22|app_user_0", 239L);
+        verify(mMockEdit).putInt("222|app_count", 1);
+        verify(mMockEdit).putString("222|app_0", "package0/class0");
+        verify(mMockEdit).putLong("222|app_user_0", 555L);
         verify(mMockEdit).apply();
         verifyNoMoreInteractions(mMockEdit);
     }
@@ -329,12 +354,12 @@
     public void testSavePrefs() {
         initializeModelFromPrefs();
 
-        mModel.savePrefs();
-        verify(mMockEdit).putInt("22|app_count", 2);
-        verify(mMockEdit).putString("22|app_0", "package1/class1");
-        verify(mMockEdit).putLong("22|app_user_0", 45L);
-        verify(mMockEdit).putString("22|app_1", "package2/class2");
-        verify(mMockEdit).putLong("22|app_user_1", 239L);
+        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);
+        verify(mMockEdit).putString("222|app_1", "package2/class2");
+        verify(mMockEdit).putLong("222|app_user_1", 555L);
         verify(mMockEdit).apply();
         verifyNoMoreInteractions(mMockEdit);
     }
@@ -367,7 +392,7 @@
 
         // Assume the user's app count pref isn't available. This will trigger clearing deleted
         // users' prefs.
-        when(mMockPrefs.getInt("22|app_count", -1)).thenReturn(-1);
+        when(mMockPrefs.getInt("222|app_count", -1)).thenReturn(-1);
 
         final Map allPrefs = new HashMap<String, Object>();
         allPrefs.put("version", null);
diff --git a/packages/WallpaperCropper/AndroidManifest.xml b/packages/WallpaperCropper/AndroidManifest.xml
index 81d1085..e558d7e 100644
--- a/packages/WallpaperCropper/AndroidManifest.xml
+++ b/packages/WallpaperCropper/AndroidManifest.xml
@@ -21,7 +21,10 @@
         <uses-permission android:name="android.permission.SET_WALLPAPER" />
         <uses-permission android:name="android.permission.SET_WALLPAPER_HINTS" />
 
-        <application android:requiredForAllUsers="true">
+        <application
+            android:requiredForAllUsers="true"
+            android:largeHeap="true">
+
         <activity
             android:name="WallpaperCropActivity"
             android:theme="@style/Theme.WallpaperCropper"
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 34aeb60..ff02b94 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -401,21 +401,40 @@
         public boolean isSystemRestore;
         public String[] filterSet;
 
-        // Restore a single package
+        /**
+         * Restore a single package; no kill after restore
+         */
         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
-                long _token, PackageInfo _pkg, int _pmToken) {
+                long _token, PackageInfo _pkg) {
             transport = _transport;
             dirName = _dirName;
             observer = _obs;
             token = _token;
             pkgInfo = _pkg;
-            pmToken = _pmToken;
+            pmToken = 0;
             isSystemRestore = false;
             filterSet = null;
         }
 
-        // Restore everything possible.  This is the form that Setup Wizard or similar
-        // restore UXes use.
+        /**
+         * Restore at install: PM token needed, kill after restore
+         */
+        RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
+                long _token, String _pkgName, int _pmToken) {
+            transport = _transport;
+            dirName = _dirName;
+            observer = _obs;
+            token = _token;
+            pkgInfo = null;
+            pmToken = _pmToken;
+            isSystemRestore = false;
+            filterSet = new String[] { _pkgName };
+        }
+
+        /**
+         * Restore everything possible.  This is the form that Setup Wizard or similar
+         * restore UXes use.
+         */
         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
                 long _token) {
             transport = _transport;
@@ -428,8 +447,10 @@
             filterSet = null;
         }
 
-        // Restore some set of packages.  Leave this one up to the caller to specify
-        // whether it's to be considered a system-level restore.
+        /**
+         * Restore some set of packages.  Leave this one up to the caller to specify
+         * whether it's to be considered a system-level restore.
+         */
         RestoreParams(IBackupTransport _transport, String _dirName, IRestoreObserver _obs,
                 long _token, String[] _filterSet, boolean _isSystemRestore) {
             transport = _transport;
@@ -1934,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);
+            }
         }
     }
 
@@ -9137,19 +9160,13 @@
                 // This can throw and so *must* happen before the wakelock is acquired
                 String dirName = transport.transportDirName();
 
-                // We can use a synthetic PackageInfo here because:
-                //   1. We know it's valid, since the Package Manager supplied the name
-                //   2. Only the packageName field will be used by the restore code
-                PackageInfo pkg = new PackageInfo();
-                pkg.packageName = packageName;
-
                 mWakelock.acquire();
                 if (MORE_DEBUG) {
                     Slog.d(TAG, "Restore at install of " + packageName);
                 }
                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
                 msg.obj = new RestoreParams(transport, dirName, null,
-                        restoreSet, pkg, token);
+                        restoreSet, packageName, token);
                 mBackupHandler.sendMessage(msg);
             } catch (RemoteException e) {
                 // Binding to the transport broke; back off and proceed with the installation.
@@ -9528,8 +9545,7 @@
                     Slog.d(TAG, "restorePackage() : " + packageName);
                 }
                 Message msg = mBackupHandler.obtainMessage(MSG_RUN_RESTORE);
-                msg.obj = new RestoreParams(mRestoreTransport, dirName,
-                        observer, token, app, 0);
+                msg.obj = new RestoreParams(mRestoreTransport, dirName, observer, token, app);
                 mBackupHandler.sendMessage(msg);
             } finally {
                 Binder.restoreCallingIdentity(oldId);
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 56ebed6..c373fb8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1569,6 +1569,8 @@
                 if ("-h".equals(arg)) {
                     dumpHelp(pw);
                     return;
+                } else if ("-a".equals(arg)) {
+                    // dump all data
                 } else if ("write-settings".equals(arg)) {
                     long token = Binder.clearCallingIdentity();
                     try {
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 13b3f8d..b826cfd 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -246,3 +246,8 @@
 # ---------------------------
 40000 volume_changed (stream|1), (prev_level|1), (level|1), (max_level|1), (caller|3)
 40001 stream_devices_changed (stream|1), (prev_devices|1), (devices|1)
+
+# ---------------------------
+# GestureLauncherService.java
+# ---------------------------
+40100 camera_gesture_triggered (gesture_on_time|2|3), (sensor1_on_time|2|3), (sensor2_on_time|2|3), (event_extra|1|1)
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 55af9f0..342a3ef 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -19,12 +19,9 @@
 import android.app.ActivityManager;
 import android.app.KeyguardManager;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.hardware.Sensor;
@@ -34,13 +31,14 @@
 import android.os.Handler;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
+import android.os.SystemClock;
 import android.os.SystemProperties;
-import android.os.UserHandle;
 import android.os.Vibrator;
-import android.provider.MediaStore;
 import android.provider.Settings;
 import android.util.Slog;
 
+import com.android.server.statusbar.StatusBarManagerInternal;
+
 /**
  * The service that listens for gestures detected in sensor firmware and starts the intent
  * accordingly.
@@ -56,8 +54,6 @@
     private final GestureEventListener mGestureListener = new GestureEventListener();
 
     private Sensor mCameraLaunchSensor;
-    private Vibrator mVibrator;
-    private KeyguardManager mKeyGuard;
     private Context mContext;
 
     /** The wake lock held when a gesture is detected. */
@@ -65,6 +61,36 @@
     private boolean mRegistered;
     private int mUserId;
 
+    // Below are fields used for event logging only.
+    /** Elapsed real time when the camera gesture is turned on. */
+    private long mCameraGestureOnTimeMs = 0L;
+
+    /** Elapsed real time when the last camera gesture was detected. */
+    private long mCameraGestureLastEventTime = 0L;
+
+    /**
+     * How long the sensor 1 has been turned on since camera launch sensor was
+     * subscribed to and when the last camera launch gesture was detected.
+     * <p>Sensor 1 is the main sensor used to detect camera launch gesture.</p>
+     */
+    private long mCameraGestureSensor1LastOnTimeMs = 0L;
+
+    /**
+     * If applicable, how long the sensor 2 has been turned on since camera
+     * launch sensor was subscribed to and when the last camera launch
+     * gesture was detected.
+     * <p>Sensor 2 is the secondary sensor used to detect camera launch gesture.
+     * This is optional and if only sensor 1 is used for detect camera launch
+     * gesture, this value would always be 0.</p>
+     */
+    private long mCameraGestureSensor2LastOnTimeMs = 0L;
+
+    /**
+     * Extra information about the event when the last camera launch gesture
+     * was detected.
+     */
+    private int mCameraLaunchLastEventExtra = 0;
+
     public GestureLauncherService(Context context) {
         super(context);
         mContext = context;
@@ -82,12 +108,9 @@
                 return;
             }
 
-            mVibrator = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
-            mKeyGuard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
             PowerManager powerManager = (PowerManager) mContext.getSystemService(
                     Context.POWER_SERVICE);
-            mWakeLock = powerManager.newWakeLock(
-                    PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP,
+            mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                     "GestureLauncherService");
             updateCameraRegistered();
 
@@ -115,6 +138,12 @@
     private void unregisterCameraLaunchGesture() {
         if (mRegistered) {
             mRegistered = false;
+            mCameraGestureOnTimeMs = 0L;
+            mCameraGestureLastEventTime = 0L;
+            mCameraGestureSensor1LastOnTimeMs = 0;
+            mCameraGestureSensor2LastOnTimeMs = 0;
+            mCameraLaunchLastEventExtra = 0;
+
             SensorManager sensorManager = (SensorManager) mContext.getSystemService(
                     Context.SENSOR_SERVICE);
             sensorManager.unregisterListener(mGestureListener);
@@ -128,6 +157,8 @@
         if (mRegistered) {
             return;
         }
+        mCameraGestureOnTimeMs = SystemClock.elapsedRealtime();
+        mCameraGestureLastEventTime = mCameraGestureOnTimeMs;
         SensorManager sensorManager = (SensorManager) mContext.getSystemService(
                 Context.SENSOR_SERVICE);
         int cameraLaunchGestureId = resources.getInteger(
@@ -208,14 +239,22 @@
     private final class GestureEventListener implements SensorEventListener {
         @Override
         public void onSensorChanged(SensorEvent event) {
+            if (!mRegistered) {
+              if (DBG) Slog.d(TAG, "Ignoring gesture event because it's unregistered.");
+              return;
+            }
             if (event.sensor == mCameraLaunchSensor) {
-                handleCameraLaunchGesture();
+                handleCameraLaunchGesture(event);
                 return;
             }
         }
 
-        private void handleCameraLaunchGesture() {
-            if (DBG) Slog.d(TAG, "Received a camera launch event.");
+        private void handleCameraLaunchGesture(SensorEvent event) {
+            if (DBG) {
+                float[] values = event.values;
+                Slog.d(TAG, String.format("Received a camera launch event: " +
+                      "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
+            }
             boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
                     Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
             if (!userSetupComplete) {
@@ -227,28 +266,13 @@
             if (DBG) Slog.d(TAG, String.format(
                     "userSetupComplete = %s, performing camera launch gesture.",
                     userSetupComplete));
-            boolean locked = mKeyGuard != null && mKeyGuard.inKeyguardRestrictedInputMode();
-            String action = locked
-                    ? MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE
-                    : MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA;
-            Intent intent = new Intent(action);
-            PackageManager pm = mContext.getPackageManager();
-            ResolveInfo componentInfo = pm.resolveActivity(intent,
-                PackageManager.MATCH_DEFAULT_ONLY);
-            if (componentInfo == null) {
-                if (DBG) Slog.d(TAG, "Couldn't find an app to process the camera intent.");
-                return;
-            }
 
-            if (mVibrator != null && mVibrator.hasVibrator()) {
-                mVibrator.vibrate(1000L);
-            }
-            // Turn on the screen before the camera launches.
+            // Make sure we don't sleep too early
             mWakeLock.acquire(500L);
-            intent.setComponent(new ComponentName(componentInfo.activityInfo.packageName,
-                    componentInfo.activityInfo.name));
-            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+            StatusBarManagerInternal service = LocalServices.getService(
+                    StatusBarManagerInternal.class);
+            service.onCameraLaunchGestureDetected();
+            trackCameraLaunchEvent(event);
             mWakeLock.release();
         }
 
@@ -256,5 +280,50 @@
         public void onAccuracyChanged(Sensor sensor, int accuracy) {
             // Ignored.
         }
+
+        private void trackCameraLaunchEvent(SensorEvent event) {
+            long now = SystemClock.elapsedRealtime();
+            long totalDuration = now - mCameraGestureOnTimeMs;
+            // values[0]: ratio between total time duration when accel is turned on and time
+            //            duration since camera launch gesture is subscribed.
+            // values[1]: ratio between total time duration when gyro is turned on and time duration
+            //            since camera launch gesture is subscribed.
+            // values[2]: extra information
+            float[] values = event.values;
+
+            long sensor1OnTime = (long) (totalDuration * (double) values[0]);
+            long sensor2OnTime = (long) (totalDuration * (double) values[1]);
+            int extra = (int) values[2];
+
+            // We only log the difference in the event log to make aggregation easier.
+            long gestureOnTimeDiff = now - mCameraGestureLastEventTime;
+            long sensor1OnTimeDiff = sensor1OnTime - mCameraGestureSensor1LastOnTimeMs;
+            long sensor2OnTimeDiff = sensor2OnTime - mCameraGestureSensor2LastOnTimeMs;
+            int extraDiff = extra - mCameraLaunchLastEventExtra;
+
+            // Gating against negative time difference. This doesn't usually happen, but it may
+            // happen because of numeric errors.
+            if (gestureOnTimeDiff < 0 || sensor1OnTimeDiff < 0 || sensor2OnTimeDiff < 0) {
+                if (DBG) Slog.d(TAG, "Skipped event logging because negative numbers.");
+                return;
+            }
+
+            if (DBG) Slog.d(TAG, String.format("totalDuration: %d, sensor1OnTime: %s, " +
+                    "sensor2OnTime: %d, extra: %d",
+                    gestureOnTimeDiff,
+                    sensor1OnTimeDiff,
+                    sensor2OnTimeDiff,
+                    extraDiff));
+            EventLogTags.writeCameraGestureTriggered(
+                    gestureOnTimeDiff,
+                    sensor1OnTimeDiff,
+                    sensor2OnTimeDiff,
+                    extraDiff);
+
+            mCameraGestureLastEventTime = now;
+            mCameraGestureSensor1LastOnTimeMs = sensor1OnTime;
+            mCameraGestureSensor2LastOnTimeMs = sensor2OnTime;
+            mCameraLaunchLastEventExtra = extra;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 0a0ee3f..b418aba 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -15,8 +15,6 @@
 
 package com.android.server;
 
-import android.annotation.NonNull;
-import android.content.pm.PackageManagerInternal;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
 import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
@@ -27,21 +25,21 @@
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethod;
-import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
 import com.android.internal.view.IInputMethodSession;
+import com.android.internal.view.IInputSessionCallback;
 import com.android.internal.view.InputBindResult;
 import com.android.server.statusbar.StatusBarManagerService;
-import com.android.server.wm.WindowManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
 
+import android.annotation.NonNull;
 import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
 import android.app.AlertDialog;
+import android.app.AppGlobals;
 import android.app.AppOpsManager;
 import android.app.IUserSwitchObserver;
 import android.app.KeyguardManager;
@@ -61,6 +59,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
@@ -80,8 +79,8 @@
 import android.os.IInterface;
 import android.os.IRemoteCallback;
 import android.os.Message;
-import android.os.Process;
 import android.os.Parcel;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
@@ -90,7 +89,6 @@
 import android.os.UserManager;
 import android.provider.Settings;
 import android.text.TextUtils;
-import android.text.TextUtils.SimpleStringSplitter;
 import android.text.style.SuggestionSpan;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -109,6 +107,7 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerInternal;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputBinding;
 import android.view.inputmethod.InputMethod;
@@ -182,11 +181,11 @@
     final InputMethodSettings mSettings;
     final SettingsObserver mSettingsObserver;
     final IWindowManager mIWindowManager;
+    final WindowManagerInternal mWindowManagerInternal;
     final HandlerCaller mCaller;
     final boolean mHasFeature;
     private InputMethodFileManager mFileManager;
     private final HardKeyboardListener mHardKeyboardListener;
-    private final WindowManagerService mWindowManagerService;
     private final AppOpsManager mAppOpsManager;
 
     final InputBindResult mNoBinding = new InputBindResult(null, null, null, -1, -1);
@@ -710,7 +709,7 @@
     }
 
     private class HardKeyboardListener
-            implements WindowManagerService.OnHardKeyboardStatusChangeListener {
+            implements WindowManagerInternal.OnHardKeyboardStatusChangeListener {
         @Override
         public void onHardKeyboardStatusChange(boolean available) {
             mHandler.sendMessage(mHandler.obtainMessage(MSG_HARD_KEYBOARD_SWITCH_CHANGED,
@@ -732,7 +731,7 @@
         }
     }
 
-    public InputMethodManagerService(Context context, WindowManagerService windowManager) {
+    public InputMethodManagerService(Context context) {
         mIPackageManager = AppGlobals.getPackageManager();
         mContext = context;
         mRes = context.getResources();
@@ -741,13 +740,13 @@
         mSettingsObserver = new SettingsObserver(mHandler);
         mIWindowManager = IWindowManager.Stub.asInterface(
                 ServiceManager.getService(Context.WINDOW_SERVICE));
+        mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
         mCaller = new HandlerCaller(context, null, new HandlerCaller.Callback() {
             @Override
             public void executeMessage(Message msg) {
                 handleMessage(msg);
             }
         }, true /*asyncHandler*/);
-        mWindowManagerService = windowManager;
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mHardKeyboardListener = new HardKeyboardListener();
         mHasFeature = context.getPackageManager().hasSystemFeature(
@@ -1045,7 +1044,7 @@
                 mShowOngoingImeSwitcherForPhones = mRes.getBoolean(
                         com.android.internal.R.bool.show_ongoing_ime_switcher);
                 if (mShowOngoingImeSwitcherForPhones) {
-                    mWindowManagerService.setOnHardKeyboardStatusChangeListener(
+                    mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
                             mHardKeyboardListener);
                 }
                 buildInputMethodListLocked(mMethodList, mMethodMap,
@@ -1507,7 +1506,7 @@
                 if (DEBUG) Slog.v(TAG, "Removing window token: " + mCurToken);
                 if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && savePosition) {
                     // The current IME is shown. Hence an IME switch (transition) is happening.
-                    mWindowManagerService.saveLastInputMethodWindowForTransition();
+                    mWindowManagerInternal.saveLastInputMethodWindowForTransition();
                 }
                 mIWindowManager.removeWindowToken(mCurToken);
             } catch (RemoteException e) {
@@ -1641,7 +1640,7 @@
         if (mSwitchingDialog != null) return false;
         if (isScreenLocked()) return false;
         if ((visibility & InputMethodService.IME_ACTIVE) == 0) return false;
-        if (mWindowManagerService.isHardKeyboardAvailable()) {
+        if (mWindowManagerInternal.isHardKeyboardAvailable()) {
             // When physical keyboard is attached, we show the ime switcher (or notification if
             // NavBar is not available) because SHOW_IME_WITH_HARD_KEYBOARD settings currently
             // exists in the IME switcher dialog.  Might be OK to remove this condition once
@@ -1753,15 +1752,18 @@
                 mImeSwitcherNotification.setContentTitle(title)
                         .setContentText(summary)
                         .setContentIntent(mImeSwitchPendingIntent);
-                if ((mNotificationManager != null)
-                        && !mWindowManagerService.hasNavigationBar()) {
-                    if (DEBUG) {
-                        Slog.d(TAG, "--- show notification: label =  " + summary);
+                try {
+                    if ((mNotificationManager != null)
+                            && !mIWindowManager.hasNavigationBar()) {
+                        if (DEBUG) {
+                            Slog.d(TAG, "--- show notification: label =  " + summary);
+                        }
+                        mNotificationManager.notifyAsUser(null,
+                                com.android.internal.R.string.select_input_method,
+                                mImeSwitcherNotification.build(), UserHandle.ALL);
+                        mNotificationShown = true;
                     }
-                    mNotificationManager.notifyAsUser(null,
-                            com.android.internal.R.string.select_input_method,
-                            mImeSwitcherNotification.build(), UserHandle.ALL);
-                    mNotificationShown = true;
+                } catch (RemoteException e) {
                 }
             } else {
                 if (mNotificationShown && mNotificationManager != null) {
@@ -2527,7 +2529,7 @@
 
     @Override
     public int getInputMethodWindowVisibleHeight() {
-        return mWindowManagerService.getInputMethodWindowVisibleHeight();
+        return mWindowManagerInternal.getInputMethodWindowVisibleHeight();
     }
 
     @Override
@@ -3041,7 +3043,7 @@
             mSwitchingDialogTitleView = tv;
             mSwitchingDialogTitleView
                     .findViewById(com.android.internal.R.id.hard_keyboard_section)
-                    .setVisibility(mWindowManagerService.isHardKeyboardAvailable()
+                    .setVisibility(mWindowManagerInternal.isHardKeyboardAvailable()
                             ? View.VISIBLE : View.GONE);
             final Switch hardKeySwitch = (Switch) mSwitchingDialogTitleView.findViewById(
                     com.android.internal.R.id.hard_keyboard_switch);
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/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 9427b61..c7e0c98 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -18,6 +18,7 @@
 
 import android.app.admin.DevicePolicyManager;
 import android.app.backup.BackupManager;
+import android.app.trust.IStrongAuthTracker;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -28,6 +29,8 @@
 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
 import static android.content.Context.USER_SERVICE;
 import static android.Manifest.permission.READ_CONTACTS;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
+
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Binder;
 import android.os.IBinder;
@@ -70,6 +73,7 @@
     private final Context mContext;
 
     private final LockSettingsStorage mStorage;
+    private final LockSettingsStrongAuth mStrongAuth = new LockSettingsStrongAuth();
 
     private LockPatternUtils mLockPatternUtils;
     private boolean mFirstCallToVold;
@@ -93,6 +97,7 @@
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_STARTING);
         filter.addAction(Intent.ACTION_USER_REMOVED);
+        filter.addAction(Intent.ACTION_USER_PRESENT);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -122,6 +127,8 @@
             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mStorage.prefetchUser(userHandle);
+            } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+                mStrongAuth.reportUnlock(getSendingUserId());
             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (userHandle > 0) {
@@ -659,6 +666,10 @@
             if (shouldReEnroll) {
                 credentialUtil.setCredential(credential, credential, userId);
             }
+        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
+            if (response.getTimeout() > 0) {
+                requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
+            }
         }
 
         return response;
@@ -713,6 +724,7 @@
 
     private void removeUser(int userId) {
         mStorage.removeUser(userId);
+        mStrongAuth.removeUser(userId);
 
         final KeyStore ks = KeyStore.getInstance();
         ks.onUserRemoved(userId);
@@ -727,6 +739,24 @@
         }
     }
 
+    @Override
+    public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+        checkPasswordReadPermission(UserHandle.USER_ALL);
+        mStrongAuth.registerStrongAuthTracker(tracker);
+    }
+
+    @Override
+    public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+        checkPasswordReadPermission(UserHandle.USER_ALL);
+        mStrongAuth.unregisterStrongAuthTracker(tracker);
+    }
+
+    @Override
+    public void requireStrongAuth(int strongAuthReason, int userId) {
+        checkWritePermission(userId);
+        mStrongAuth.requireStrongAuth(strongAuthReason, userId);
+    }
+
     private static final String[] VALID_SETTINGS = new String[] {
         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -797,5 +827,4 @@
         Slog.e(TAG, "Unable to acquire GateKeeperService");
         return null;
     }
-
 }
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
new file mode 100644
index 0000000..c023f4a
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -0,0 +1,167 @@
+/*
+ * 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;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
+
+import android.app.trust.IStrongAuthTracker;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+
+/**
+ * Keeps track of requests for strong authentication.
+ */
+public class LockSettingsStrongAuth {
+
+    private static final String TAG = "LockSettings";
+
+    private static final int MSG_REQUIRE_STRONG_AUTH = 1;
+    private static final int MSG_REGISTER_TRACKER = 2;
+    private static final int MSG_UNREGISTER_TRACKER = 3;
+    private static final int MSG_REMOVE_USER = 4;
+
+    private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+    private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+
+    private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
+        for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+            if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+                return;
+            }
+        }
+        mStrongAuthTrackers.add(tracker);
+
+        for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+            int key = mStrongAuthForUser.keyAt(i);
+            int value = mStrongAuthForUser.valueAt(i);
+            try {
+                tracker.onStrongAuthRequiredChanged(value, key);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
+            }
+        }
+    }
+
+    private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
+        for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+            if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+                mStrongAuthTrackers.remove(i);
+                return;
+            }
+        }
+    }
+
+    private void handleRequireStrongAuth(int strongAuthReason, int userId) {
+        if (userId == UserHandle.USER_ALL) {
+            for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+                int key = mStrongAuthForUser.keyAt(i);
+                handleRequireStrongAuthOneUser(strongAuthReason, key);
+            }
+        } else {
+            handleRequireStrongAuthOneUser(strongAuthReason, userId);
+        }
+    }
+
+    private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
+        int oldValue = mStrongAuthForUser.get(userId, LockPatternUtils.StrongAuthTracker.DEFAULT);
+        int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
+                ? STRONG_AUTH_NOT_REQUIRED
+                : (oldValue | strongAuthReason);
+        if (oldValue != newValue) {
+            mStrongAuthForUser.put(userId, newValue);
+            notifyStrongAuthTrackers(newValue, userId);
+        }
+    }
+
+    private void handleRemoveUser(int userId) {
+        int index = mStrongAuthForUser.indexOfKey(userId);
+        if (index >= 0) {
+            mStrongAuthForUser.removeAt(index);
+            notifyStrongAuthTrackers(StrongAuthTracker.DEFAULT, userId);
+        }
+    }
+
+    private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
+        for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+            try {
+                mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
+            } catch (DeadObjectException e) {
+                Slog.d(TAG, "Removing dead StrongAuthTracker.");
+                mStrongAuthTrackers.remove(i);
+                i--;
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+            }
+        }
+    }
+
+    public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+        mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
+    }
+
+    public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+        mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget();
+    }
+
+    public void removeUser(int userId) {
+        mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
+    }
+
+    public void requireStrongAuth(int strongAuthReason, int userId) {
+        if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
+            mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
+                    userId).sendToTarget();
+        } else {
+            throw new IllegalArgumentException(
+                    "userId must be an explicit user id or USER_ALL");
+        }
+    }
+
+    public void reportUnlock(int userId) {
+        requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
+    }
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_REGISTER_TRACKER:
+                    handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj);
+                    break;
+                case MSG_UNREGISTER_TRACKER:
+                    handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj);
+                    break;
+                case MSG_REQUIRE_STRONG_AUTH:
+                    handleRequireStrongAuth(msg.arg1, msg.arg2);
+                    break;
+                case MSG_REMOVE_USER:
+                    handleRemoveUser(msg.arg1);
+                    break;
+            }
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 0d64540..72cece3 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -165,6 +165,8 @@
         public void onBootPhase(int phase) {
             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                 mMountService.systemReady();
+            } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+                mMountService.bootCompleted();
             }
         }
 
@@ -405,6 +407,7 @@
     private final NativeDaemonConnector mCryptConnector;
 
     private volatile boolean mSystemReady = false;
+    private volatile boolean mBootCompleted = false;
     private volatile boolean mDaemonConnected = false;
 
     private PackageManagerService mPms;
@@ -1244,7 +1247,9 @@
 
         mCallbacks.notifyVolumeStateChanged(vol, oldState, newState);
 
-        if (isBroadcastWorthy(vol)) {
+        // Do not broadcast before boot has completed to avoid launching the
+        // processes that receive the intent unnecessarily.
+        if (mBootCompleted && isBroadcastWorthy(vol)) {
             final Intent intent = new Intent(VolumeInfo.ACTION_VOLUME_STATE_CHANGED);
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
             intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
@@ -1429,6 +1434,10 @@
         mHandler.obtainMessage(H_SYSTEM_READY).sendToTarget();
     }
 
+    private void bootCompleted() {
+        mBootCompleted = true;
+    }
+
     private String getDefaultPrimaryStorageUuid() {
         if (SystemProperties.getBoolean(StorageManager.PROP_PRIMARY_PHYSICAL, false)) {
             return StorageManager.UUID_PRIMARY_PHYSICAL;
diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java
index cd61347..86183af 100644
--- a/services/core/java/com/android/server/SystemConfig.java
+++ b/services/core/java/com/android/server/SystemConfig.java
@@ -99,6 +99,12 @@
     // URL-handling state upon factory reset.
     final ArraySet<String> mLinkedApps = new ArraySet<>();
 
+    // These are the packages that are whitelisted to be able to run as system user
+    final ArraySet<String> mSystemUserWhitelistedApps = new ArraySet<>();
+
+    // These are the packages that should not run under system user
+    final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
+
     public static SystemConfig getInstance() {
         synchronized (SystemConfig.class) {
             if (sInstance == null) {
@@ -144,6 +150,14 @@
         return mLinkedApps;
     }
 
+    public ArraySet<String> getSystemUserWhitelistedApps() {
+        return mSystemUserWhitelistedApps;
+    }
+
+    public ArraySet<String> getSystemUserBlacklistedApps() {
+        return mSystemUserBlacklistedApps;
+    }
+
     SystemConfig() {
         // Read configuration from system
         readPermissions(Environment.buildPath(
@@ -380,7 +394,24 @@
                         mLinkedApps.add(pkgname);
                     }
                     XmlUtils.skipCurrentTag(parser);
-
+                } else if ("system-user-whitelisted-app".equals(name)) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<system-user-whitelisted-app> without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mSystemUserWhitelistedApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
+                } else if ("system-user-blacklisted-app".equals(name)) {
+                    String pkgname = parser.getAttributeValue(null, "package");
+                    if (pkgname == null) {
+                        Slog.w(TAG, "<system-user-blacklisted-app without package in " + permFile
+                                + " at " + parser.getPositionDescription());
+                    } else {
+                        mSystemUserBlacklistedApps.add(pkgname);
+                    }
+                    XmlUtils.skipCurrentTag(parser);
                 } else {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
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/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 55a2659..4aef23b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -19,8 +19,10 @@
 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;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
@@ -53,6 +55,7 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
+import android.content.pm.AppsQueryHelper;
 import android.content.pm.PermissionInfo;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
@@ -100,6 +103,7 @@
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
 import com.android.server.ServiceThread;
+import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
 import com.android.server.Watchdog;
@@ -207,7 +211,6 @@
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.SELinux;
 import android.os.ServiceManager;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -2698,6 +2701,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);
@@ -9005,8 +9042,7 @@
         synchronized (this) {
             ActivityStack stack = ActivityRecord.getStackLocked(token);
             if (stack == null) {
-                throw new IllegalArgumentException(
-                        "getActivityStackId: No stack for token=" + token);
+                return INVALID_STACK_ID;
             }
             return stack.mStackId;
         }
@@ -9028,7 +9064,7 @@
                 }
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r
                         + " to stackId=" + stackId);
-                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, FORCE_FOCUS);
+                mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -11983,6 +12019,8 @@
                 }
             }
 
+            enableSystemUserApps();
+
             // Start up initial activity.
             mBooting = true;
             startHomeActivityLocked(mCurrentUserId, "systemReady");
@@ -12033,6 +12071,42 @@
         }
     }
 
+    private void enableSystemUserApps() {
+        // For system user, enable apps based on the following conditions:
+        // - app is whitelisted; or has no launcher icons; or has INTERACT_ACROSS_USERS permission
+        // - app is not in the blacklist
+        if (UserManager.isSplitSystemUser()) {
+            AppsQueryHelper queryHelper = new AppsQueryHelper(mContext);
+            Set<String> enableApps = new HashSet<>();
+            enableApps.addAll(queryHelper.queryApps(AppsQueryHelper.GET_NON_LAUNCHABLE_APPS
+                            | AppsQueryHelper.GET_APPS_WITH_INTERACT_ACROSS_USERS_PERM,
+                            /* systemAppsOnly */ true, UserHandle.SYSTEM));
+            ArraySet<String> wlApps = SystemConfig.getInstance().getSystemUserWhitelistedApps();
+            enableApps.addAll(wlApps);
+            ArraySet<String> blApps = SystemConfig.getInstance().getSystemUserBlacklistedApps();
+            enableApps.removeAll(blApps);
+
+            List<String> systemApps = queryHelper.queryApps(0, /* systemAppsOnly */ true,
+                    UserHandle.SYSTEM);
+            final int systemAppsSize = systemApps.size();
+            for (int i = 0; i < systemAppsSize; i++) {
+                String pName = systemApps.get(i);
+                boolean enable = enableApps.contains(pName);
+                try {
+                    if (enable) {
+                        AppGlobals.getPackageManager().installExistingPackageAsUser(pName,
+                                UserHandle.USER_SYSTEM);
+                    } else {
+                        AppGlobals.getPackageManager().deletePackageAsUser(pName, null,
+                                UserHandle.USER_SYSTEM, PackageManager.DELETE_SYSTEM_APP);
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Error occured when processing package " + pName, e);
+                }
+            }
+        }
+    }
+
     private boolean makeAppCrashingLocked(ProcessRecord app,
             String shortMsg, String longMsg, String stackTrace) {
         app.crashing = true;
@@ -16541,12 +16615,12 @@
                 }
                 List<ResolveInfo> newReceivers = AppGlobals.getPackageManager()
                         .queryIntentReceivers(intent, resolvedType, STOCK_PM_FLAGS, user);
-                if (user != UserHandle.USER_OWNER && newReceivers != null) {
-                    // If this is not the primary user, we need to check for
+                if (user != UserHandle.USER_SYSTEM && newReceivers != null) {
+                    // If this is not the system user, we need to check for
                     // any receivers that should be filtered out.
                     for (int i=0; i<newReceivers.size(); i++) {
                         ResolveInfo ri = newReceivers.get(i);
-                        if ((ri.activityInfo.flags&ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
+                        if ((ri.activityInfo.flags&ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
                             newReceivers.remove(i);
                             i--;
                         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index fcd596f..f50df3a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -902,7 +902,14 @@
         prev.task.touchActiveTime();
         clearLaunchTime(prev);
         final ActivityRecord next = mStackSupervisor.topRunningActivityLocked();
-        if (mService.mHasRecents && (next == null || next.noDisplay || next.task != prev.task || uiSleeping)) {
+        // In freeform mode we only update the thumbnail when there is no thumbnail yet since every
+        // focus change will request a thumbnail to be taken.
+        // Note furthermore that since windows can change their content in freeform mode all the
+        // time a thumbnail is possibly constantly outdated.
+        if (mService.mHasRecents &&
+                (next == null || next.noDisplay || next.task != prev.task || uiSleeping) &&
+                (!prev.task.hasThumbnail() ||
+                        prev.task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID)) {
             prev.updateThumbnailLocked(screenshotActivities(prev), null);
         }
         stopFullyDrawnTraceIfNeeded();
@@ -4543,7 +4550,7 @@
         TaskRecord task = new TaskRecord(mService, taskId, info, intent, voiceSession,
                 voiceInteractor);
         if (mTaskPositioner != null) {
-            mTaskPositioner.updateDefaultBounds(task, mTaskHistory);
+            mTaskPositioner.updateDefaultBounds(task, mTaskHistory, info.initialLayout);
         }
         addTask(task, toTop, false);
         return task;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 0bdeed7..c86056b 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3017,7 +3017,6 @@
         // Place the task in the right stack if it isn't there already based on the requested
         // bounds.
         int stackId = task.stack.mStackId;
-        final boolean wasFrontStack = isFrontStack(task.stack);
         if (bounds == null && stackId != FULLSCREEN_WORKSPACE_STACK_ID) {
             stackId = FULLSCREEN_WORKSPACE_STACK_ID;
         } else if (bounds != null
@@ -3027,12 +3026,7 @@
         if (stackId != task.stack.mStackId) {
             final String reason = "resizeTask";
             final ActivityStack stack =
-                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, reason);
-            if (wasFrontStack) {
-                // Since the stack was previously in front,
-                // move the stack in which we are placing the task to the front.
-                stack.moveToFront(reason);
-            }
+                    moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
         }
 
         final Configuration overrideConfig = mWindowManager.resizeTask(task.taskId, bounds);
@@ -3126,17 +3120,36 @@
      * @param task Task to move.
      * @param stackId Id of stack to move task to.
      * @param toTop True if the task should be placed at the top of the stack.
+     * @param forceFocus if focus should be moved to the new stack
      * @param reason Reason the task is been moved.
      * @return The stack the task was moved to.
      */
     private ActivityStack moveTaskToStackUncheckedLocked(
-            TaskRecord task, int stackId, boolean toTop, String reason) {
+            TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+        final ActivityRecord r = task.getTopActivity();
+        final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+
         final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
         mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
         if (task.stack != null) {
             task.stack.removeTask(task, reason, MOVING);
         }
         stack.addTask(task, toTop, MOVING);
+
+        // If the task had focus before (or we're requested to move focus),
+        // move focus to the new stack.
+        if (forceFocus || wasFocused) {
+            // If the task owns the last resumed activity, transfer that together,
+            // so that we don't resume the same activity again in the new stack.
+            // Apps may depend on onResume()/onPause() being called in pairs.
+            if (wasResumed) {
+                stack.mResumedActivity = r;
+            }
+            // move the stack in which we are placing the task to the front.
+            stack.moveToFront(reason);
+        }
+
         return stack;
     }
 
@@ -3147,10 +3160,8 @@
             return;
         }
         final String reason = "moveTaskToStack";
-        final ActivityRecord top = task.topRunningActivityLocked(null);
-        final boolean adjustFocus = forceFocus || mService.mFocusedActivity == top;
         final ActivityStack stack =
-                moveTaskToStackUncheckedLocked(task, stackId, toTop, reason);
+                moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason);
 
         // Make sure the task has the appropriate bounds/size for the stack it is in.
         if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) {
@@ -3162,14 +3173,6 @@
             resizeTaskLocked(task, stack.mBounds);
         }
 
-        if (top != null && adjustFocus) {
-            if (mService.mFocusedActivity != top) {
-                mService.setFocusedActivityLocked(top, reason);
-            } else {
-                setFocusedStack(top, reason);
-            }
-        }
-
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 9bf4f5f..335288d 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -1263,8 +1263,8 @@
                     Slog.v(TAG, "WiFi energy data was reset, new WiFi energy data is " + result);
                 }
 
-                // There is some accuracy error in reports so allow 30 milliseconds of error.
-                final long SAMPLE_ERROR_MILLIS = 30;
+                // There is some accuracy error in reports so allow some slop in the results.
+                final long SAMPLE_ERROR_MILLIS = 750;
                 final long totalTimeMs = result.mControllerIdleTimeMs + result.mControllerRxTimeMs +
                         result.mControllerTxTimeMs;
                 if (totalTimeMs > timePeriodMs + SAMPLE_ERROR_MILLIS) {
diff --git a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
index 3005c86..5c4fd13 100644
--- a/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
+++ b/services/core/java/com/android/server/am/LaunchingTaskPositioner.java
@@ -16,16 +16,30 @@
 
 package com.android.server.am;
 
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+
+import android.annotation.Nullable;
+import android.content.pm.ActivityInfo;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.util.Slog;
 import android.view.Display;
+import android.view.Gravity;
 
 import java.util.ArrayList;
 
 /**
  * Determines where a launching task should be positioned and sized on the display.
+ *
+ * The positioner is fairly simple. For the new task it tries default position based on the gravity
+ * and compares corners of the task with corners of existing tasks. If some two pairs of corners are
+ * sufficiently close enough, it shifts the bounds of the new task and tries again. When it exhausts
+ * all possible shifts, it gives up and puts the task in the original position.
  */
 class LaunchingTaskPositioner {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "LaunchingTaskPositioner" : TAG_AM;
+
     // Determines how close window frames/corners have to be to call them colliding.
     private static final int BOUNDS_CONFLICT_MIN_DISTANCE = 4;
 
@@ -42,8 +56,19 @@
     // We always want to step by at least this.
     private static final int MINIMAL_STEP = 1;
 
+    // Used to indicate if positioning algorithm is allowed to restart from the beginning, when it
+    // reaches the end of stack bounds.
+    private static final boolean ALLOW_RESTART = true;
+
+    private static final int SHIFT_POLICY_DIAGONAL_DOWN = 1;
+    private static final int SHIFT_POLICY_HORIZONTAL_RIGHT = 2;
+    private static final int SHIFT_POLICY_HORIZONTAL_LEFT = 3;
+
     private boolean mDefaultStartBoundsConfigurationSet = false;
     private final Rect mAvailableRect = new Rect();
+    private final Rect mTmpProposal = new Rect();
+    private final Rect mTmpOriginal = new Rect();
+
     private int mDefaultFreeformStartX;
     private int mDefaultFreeformStartY;
     private int mDefaultFreeformWidth;
@@ -84,51 +109,167 @@
      *
      * @param task Task for which we want to find bounds that won't collide with other.
      * @param tasks Existing tasks with which we don't want to collide.
+     * @param initialLayout Optional information from the client about how it would like to be sized
+     *                      and positioned.
      */
-    void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks) {
+    void updateDefaultBounds(TaskRecord task, ArrayList<TaskRecord> tasks,
+            @Nullable ActivityInfo.InitialLayout initialLayout) {
         if (!mDefaultStartBoundsConfigurationSet) {
             return;
         }
-        int startX = mDefaultFreeformStartX;
-        int startY = mDefaultFreeformStartY;
-        final int right = mAvailableRect.right;
-        final int bottom = mAvailableRect.bottom;
+        if (initialLayout == null) {
+            positionCenter(task, tasks, mDefaultFreeformWidth, mDefaultFreeformHeight);
+            return;
+        }
+        int width = getFinalWidth(initialLayout);
+        int height = getFinalHeight(initialLayout);
+        int verticalGravity = initialLayout.gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        int horizontalGravity = initialLayout.gravity & Gravity.HORIZONTAL_GRAVITY_MASK;
+        if (verticalGravity == Gravity.TOP) {
+            if (horizontalGravity == Gravity.RIGHT) {
+                positionTopRight(task, tasks, width, height);
+            } else {
+                positionTopLeft(task, tasks, width, height);
+            }
+        } else if (verticalGravity == Gravity.BOTTOM) {
+            if (horizontalGravity == Gravity.RIGHT) {
+                positionBottomRight(task, tasks, width, height);
+            } else {
+                positionBottomLeft(task, tasks, width, height);
+            }
+        } else {
+            // Some fancy gravity setting that we don't support yet. We just put the activity in the
+            // center.
+            Slog.w(TAG, "Received unsupported gravity: " + initialLayout.gravity
+                    + ", positioning in the center instead.");
+            positionCenter(task, tasks, width, height);
+        }
+    }
+
+    private int getFinalWidth(ActivityInfo.InitialLayout initialLayout) {
+        int width = mDefaultFreeformWidth;
+        if (initialLayout.width > 0) {
+            width = initialLayout.width;
+        }
+        if (initialLayout.widthFraction > 0) {
+            width = (int) (mAvailableRect.width() * initialLayout.widthFraction);
+        }
+        return width;
+    }
+
+    private int getFinalHeight(ActivityInfo.InitialLayout initialLayout) {
+        int height = mDefaultFreeformHeight;
+        if (initialLayout.height > 0) {
+            height = initialLayout.height;
+        }
+        if (initialLayout.heightFraction > 0) {
+            height = (int) (mAvailableRect.height() * initialLayout.heightFraction);
+        }
+        return height;
+    }
+
+    private void positionBottomLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+            int height) {
+        mTmpProposal.set(mAvailableRect.left, mAvailableRect.bottom - height,
+                mAvailableRect.left + width, mAvailableRect.bottom);
+        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+    }
+
+    private void positionBottomRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+            int height) {
+        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.bottom - height,
+                mAvailableRect.right, mAvailableRect.bottom);
+        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+    }
+
+    private void positionTopLeft(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+            int height) {
+        mTmpProposal.set(mAvailableRect.left, mAvailableRect.top,
+                mAvailableRect.left + width, mAvailableRect.top + height);
+        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_RIGHT);
+    }
+
+    private void positionTopRight(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+            int height) {
+        mTmpProposal.set(mAvailableRect.right - width, mAvailableRect.top,
+                mAvailableRect.right, mAvailableRect.top + height);
+        position(task, tasks, mTmpProposal, !ALLOW_RESTART, SHIFT_POLICY_HORIZONTAL_LEFT);
+    }
+
+    private void positionCenter(TaskRecord task, ArrayList<TaskRecord> tasks, int width,
+            int height) {
+        mTmpProposal.set(mDefaultFreeformStartX, mDefaultFreeformStartY,
+                mDefaultFreeformStartX + width, mDefaultFreeformStartY + height);
+        position(task, tasks, mTmpProposal, ALLOW_RESTART, SHIFT_POLICY_DIAGONAL_DOWN);
+    }
+
+    private void position(TaskRecord task, ArrayList<TaskRecord> tasks, Rect proposal,
+            boolean allowRestart, int shiftPolicy) {
+        mTmpOriginal.set(proposal);
         boolean restarted = false;
-        while (boundsConflict(startX, startY, tasks)) {
+        while (boundsConflict(proposal, tasks)) {
             // Unfortunately there is already a task at that spot, so we need to look for some
             // other place.
-            startX += mDefaultFreeformStepHorizontal;
-            startY += mDefaultFreeformStepVertical;
-            if (startX + mDefaultFreeformWidth > right
-                    || startY + mDefaultFreeformHeight > bottom) {
-                // We don't want the task to go outside of the display, because it won't look
-                // nice. Let's restart from the top instead, because there should be some space
-                // there.
-                startX = mAvailableRect.left;
-                startY = mAvailableRect.top;
+            shiftStartingPoint(proposal, shiftPolicy);
+            if (shiftedToFar(proposal, shiftPolicy)) {
+                // We don't want the task to go outside of the stack, because it won't look
+                // nice. Depending on the starting point we either restart, or immediately give up.
+                if (!allowRestart) {
+                    proposal.set(mTmpOriginal);
+                    break;
+                }
+                // We must have started not from the top. Let's restart from there because there
+                // might be some space there.
+                proposal.set(mAvailableRect.left, mAvailableRect.top,
+                        mAvailableRect.left + proposal.width(),
+                        mAvailableRect.top + proposal.height());
                 restarted = true;
             }
-            if (restarted
-                    && (startX > mDefaultFreeformStartX || startY > mDefaultFreeformStartY)) {
+            if (restarted && (proposal.left > mDefaultFreeformStartX
+                    || proposal.top > mDefaultFreeformStartY)) {
                 // If we restarted and crossed the initial position, let's not struggle anymore.
                 // The user already must have ton of tasks visible, we can just smack the new
                 // one in the center.
-                startX = mDefaultFreeformStartX;
-                startY = mDefaultFreeformStartY;
+                proposal.set(mTmpOriginal);
                 break;
             }
         }
-        task.setInitialBounds(startX, startY, startX + mDefaultFreeformWidth,
-                startY + mDefaultFreeformHeight);
+        task.setInitialBounds(proposal);
     }
 
-    private boolean boundsConflict(int startX, int startY, ArrayList<TaskRecord> tasks) {
+    private boolean shiftedToFar(Rect start, int shiftPolicy) {
+        switch (shiftPolicy) {
+            case SHIFT_POLICY_HORIZONTAL_LEFT:
+                return start.left < mAvailableRect.left;
+            case SHIFT_POLICY_HORIZONTAL_RIGHT:
+                return start.right > mAvailableRect.right;
+            default: // SHIFT_POLICY_DIAGONAL_DOWN
+                return start.right > mAvailableRect.right || start.bottom > mAvailableRect.bottom;
+        }
+    }
+
+    private void shiftStartingPoint(Rect posposal, int shiftPolicy) {
+        switch (shiftPolicy) {
+            case SHIFT_POLICY_HORIZONTAL_LEFT:
+                posposal.offset(-mDefaultFreeformStepHorizontal, 0);
+                break;
+            case SHIFT_POLICY_HORIZONTAL_RIGHT:
+                posposal.offset(mDefaultFreeformStepHorizontal, 0);
+                break;
+            default: // SHIFT_POLICY_DIAGONAL_DOWN:
+                posposal.offset(mDefaultFreeformStepHorizontal, mDefaultFreeformStepVertical);
+                break;
+        }
+    }
+
+    private static boolean boundsConflict(Rect proposal, ArrayList<TaskRecord> tasks) {
         for (int i = tasks.size() - 1; i >= 0; i--) {
             TaskRecord task = tasks.get(i);
-            if (!task.mActivities.isEmpty()) {
+            if (!task.mActivities.isEmpty() && task.mBounds != null) {
                 Rect bounds = task.mBounds;
-                if (bounds != null && (Math.abs(bounds.left - startX) < BOUNDS_CONFLICT_MIN_DISTANCE
-                        || Math.abs(bounds.top - startY) < BOUNDS_CONFLICT_MIN_DISTANCE)) {
+                if (closeLeftTopCorner(proposal, bounds) || closeRightTopCorner(proposal, bounds)
+                        || closeLeftBottomCorner(proposal, bounds)
+                        || closeRightBottomCorner(proposal, bounds)) {
                     return true;
                 }
             }
@@ -136,6 +277,26 @@
         return false;
     }
 
+    private static final boolean closeLeftTopCorner(Rect first, Rect second) {
+        return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
+                && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    }
+
+    private static final boolean closeRightTopCorner(Rect first, Rect second) {
+        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
+                && Math.abs(first.top - second.top) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    }
+
+    private static final boolean closeLeftBottomCorner(Rect first, Rect second) {
+        return Math.abs(first.left - second.left) < BOUNDS_CONFLICT_MIN_DISTANCE
+                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    }
+
+    private static final boolean closeRightBottomCorner(Rect first, Rect second) {
+        return Math.abs(first.right - second.right) < BOUNDS_CONFLICT_MIN_DISTANCE
+                && Math.abs(first.bottom - second.bottom) < BOUNDS_CONFLICT_MIN_DISTANCE;
+    }
+
     void reset() {
         mDefaultStartBoundsConfigurationSet = false;
     }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index ff412d1..9cbaec5 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -478,6 +478,14 @@
     }
 
     /**
+     * Returns true when we have a thumbnail.
+     * @return Returns true if there is a thumbnail.
+     */
+    boolean hasThumbnail() {
+        return mLastThumbnail != null;
+    }
+
+    /**
      * Sets the last thumbnail.
      * @return whether the thumbnail was set
      */
@@ -1217,11 +1225,11 @@
         return mLastNonFullscreenBounds;
     }
 
-    void setInitialBounds(int left, int top, int right, int bottom) {
+    void setInitialBounds(Rect rect) {
         if (mBounds == null) {
             mBounds = new Rect();
         }
-        mBounds.set(left, top, right, bottom);
+        mBounds.set(rect);
         mLastNonFullscreenBounds = mBounds;
     }
 
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index 0be24f4..f82454a 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -23,13 +23,17 @@
 import android.content.pm.UserInfo;
 import android.hardware.ICameraService;
 import android.hardware.ICameraServiceProxy;
+import android.nfc.INfcAdapter;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Binder;
 import android.os.Message;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserManager;
+import android.os.SystemProperties;
 import android.util.Slog;
+import android.util.ArraySet;
 
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
@@ -44,8 +48,10 @@
  *
  * @hide
  */
-public class CameraService extends SystemService implements Handler.Callback {
+public class CameraService extends SystemService
+        implements Handler.Callback, IBinder.DeathRecipient {
     private static final String TAG = "CameraService_proxy";
+    private static final boolean DEBUG = false;
 
     /**
      * This must match the ICameraService.aidl definition
@@ -58,6 +64,16 @@
     public static final int NO_EVENT = 0; // NOOP
     public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
 
+    // State arguments to use with the notifyCameraState call from camera service:
+    public static final int CAMERA_STATE_OPEN = 0;
+    public static final int CAMERA_STATE_ACTIVE = 1;
+    public static final int CAMERA_STATE_IDLE = 2;
+    public static final int CAMERA_STATE_CLOSED = 3;
+
+    // Flags arguments to NFC adapter to enable/disable NFC
+    public static final int DISABLE_POLLING_FLAGS = 0x1000;
+    public static final int ENABLE_POLLING_FLAGS = 0x0000;
+
     // Handler message codes
     private static final int MSG_SWITCH_USER = 1;
 
@@ -72,6 +88,17 @@
     private Set<Integer> mEnabledCameraUsers;
     private int mLastUser;
 
+    private ICameraService mCameraServiceRaw;
+
+    private final ArraySet<String> mActiveCameraIds = new ArraySet<>();
+
+    private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc";
+    private static final String NFC_SERVICE_BINDER_NAME = "nfc";
+    private static final IBinder nfcInterfaceToken = new Binder();
+
+    private final boolean mNotifyNfc;
+    private int mActiveCameraCount = 0;
+
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -102,6 +129,14 @@
         public void pingForUserUpdate() {
             notifySwitchWithRetries(30);
         }
+
+        @Override
+        public void notifyCameraState(String cameraId, int newCameraState) {
+            String state = cameraStateToString(newCameraState);
+            if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " state now " + state);
+
+            updateActivityCount(cameraId, newCameraState);
+        }
     };
 
     public CameraService(Context context) {
@@ -110,6 +145,9 @@
         mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_DISPLAY, /*allowTo*/false);
         mHandlerThread.start();
         mHandler = new Handler(mHandlerThread.getLooper(), this);
+
+        mNotifyNfc = SystemProperties.getInt(NFC_NOTIFICATION_PROP, 0) > 0;
+        if (DEBUG) Slog.v(TAG, "Notify NFC behavior is " + (mNotifyNfc ? "active" : "disabled"));
     }
 
     @Override
@@ -161,13 +199,32 @@
         }
     }
 
+    /**
+     * Handle the death of the native camera service
+     */
+    @Override
+    public void binderDied() {
+        if (DEBUG) Slog.w(TAG, "Native camera service has died");
+        synchronized(mLock) {
+            mCameraServiceRaw = null;
+
+            // All cameras reset to idle on camera service death
+            boolean wasEmpty = mActiveCameraIds.isEmpty();
+            mActiveCameraIds.clear();
+
+            if ( mNotifyNfc && !wasEmpty ) {
+                notifyNfcService(/*enablePolling*/ true);
+            }
+        }
+    }
+
     private void switchUserLocked(int userHandle) {
         Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
         mLastUser = userHandle;
         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
             // Some user handles have been added or removed, update mediaserver.
             mEnabledCameraUsers = currentUserHandles;
-            notifyMediaserver(USER_SWITCHED, currentUserHandles);
+            notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
         }
     }
 
@@ -187,7 +244,7 @@
             if (mEnabledCameraUsers == null) {
                 return;
             }
-            if (notifyMediaserver(USER_SWITCHED, mEnabledCameraUsers)) {
+            if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
                 retries = 0;
             }
         }
@@ -199,19 +256,27 @@
                 RETRY_DELAY_TIME);
     }
 
-    private boolean notifyMediaserver(int eventType, Set<Integer> updatedUserHandles) {
+    private boolean notifyMediaserverLocked(int eventType, Set<Integer> updatedUserHandles) {
         // Forward the user switch event to the native camera service running in the mediaserver
         // process.
-        IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
-        if (cameraServiceBinder == null) {
-            Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
-            return false; // Camera service not active, cannot evict user clients.
+        if (mCameraServiceRaw == null) {
+            IBinder cameraServiceBinder = getBinderService(CAMERA_SERVICE_BINDER_NAME);
+            if (cameraServiceBinder == null) {
+                Slog.w(TAG, "Could not notify mediaserver, camera service not available.");
+                return false; // Camera service not active, cannot evict user clients.
+            }
+            try {
+                cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Could not link to death of native camera service");
+                return false;
+            }
+
+            mCameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
         }
 
-        ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
         try {
-            cameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
+            mCameraServiceRaw.notifySystemEvent(eventType, toArray(updatedUserHandles));
         } catch (RemoteException e) {
             Slog.w(TAG, "Could not notify mediaserver, remote exception: " + e);
             // Not much we can do if camera service is dead.
@@ -220,6 +285,44 @@
         return true;
     }
 
+    private void updateActivityCount(String cameraId, int newCameraState) {
+        synchronized(mLock) {
+            boolean wasEmpty = mActiveCameraIds.isEmpty();
+            switch (newCameraState) {
+                case CAMERA_STATE_OPEN:
+                    break;
+                case CAMERA_STATE_ACTIVE:
+                    mActiveCameraIds.add(cameraId);
+                    break;
+                case CAMERA_STATE_IDLE:
+                case CAMERA_STATE_CLOSED:
+                    mActiveCameraIds.remove(cameraId);
+                    break;
+            }
+            boolean isEmpty = mActiveCameraIds.isEmpty();
+            if ( mNotifyNfc && (wasEmpty != isEmpty) ) {
+                notifyNfcService(isEmpty);
+            }
+        }
+    }
+
+    private void notifyNfcService(boolean enablePolling) {
+
+        IBinder nfcServiceBinder = getBinderService(NFC_SERVICE_BINDER_NAME);
+        if (nfcServiceBinder == null) {
+            Slog.w(TAG, "Could not connect to NFC service to notify it of camera state");
+            return;
+        }
+        INfcAdapter nfcAdapterRaw = INfcAdapter.Stub.asInterface(nfcServiceBinder);
+        int flags = enablePolling ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
+        if (DEBUG) Slog.v(TAG, "Setting NFC reader mode to flags " + flags);
+        try {
+            nfcAdapterRaw.setReaderMode(nfcInterfaceToken, null, flags, null);
+        } catch (RemoteException e) {
+            Slog.w(TAG, "Could not notify NFC service, remote exception: " + e);
+        }
+    }
+
     private static int[] toArray(Collection<Integer> c) {
         int len = c.size();
         int[] ret = new int[len];
@@ -229,4 +332,15 @@
         }
         return ret;
     }
+
+    private static String cameraStateToString(int newCameraState) {
+        switch (newCameraState) {
+            case CAMERA_STATE_OPEN: return "CAMERA_STATE_OPEN";
+            case CAMERA_STATE_ACTIVE: return "CAMERA_STATE_ACTIVE";
+            case CAMERA_STATE_IDLE: return "CAMERA_STATE_IDLE";
+            case CAMERA_STATE_CLOSED: return "CAMERA_STATE_CLOSED";
+            default: break;
+        }
+        return "CAMERA_STATE_UNKNOWN";
+    }
 }
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 2846185..3df3cd0 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -146,7 +146,8 @@
         } catch (RemoteException e) {
             Log.wtf(TAG, "Problem registering observer", e);
         }
-        if (userHandle == UserHandle.USER_OWNER) {
+        // TODO: http://b/22950929
+        if (userHandle == UserHandle.USER_SYSTEM) {
             // Owner's VPN also needs to handle restricted users
             mUserIntentReceiver = new BroadcastReceiver() {
                 @Override
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index befa311..7e46db8 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -129,7 +129,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 +157,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 +167,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 +177,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 +193,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 +203,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 +215,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 +226,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();
@@ -298,6 +298,7 @@
             final int result = daemon.enroll(cryptoToken, groupId, timeout);
             if (result != 0) {
                 Slog.w(TAG, "startEnroll failed, result=" + result);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startEnroll failed", e);
@@ -391,6 +392,7 @@
             final int result = daemon.authenticate(opId, groupId);
             if (result != 0) {
                 Slog.w(TAG, "startAuthentication failed, result=" + result);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startAuthentication failed", e);
@@ -433,12 +435,14 @@
             return;
         }
 
+        stopPendingOperations(true);
         mRemoveClient = new ClientMonitor(token, receiver, userId, restricted);
         // The fingerprint template ids will be removed when we get confirmation from the HAL
         try {
             final int result = daemon.remove(fingerId, userId);
             if (result != 0) {
                 Slog.w(TAG, "startRemove with id = " + fingerId + " failed, result=" + result);
+                handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
             }
         } catch (RemoteException e) {
             Slog.e(TAG, "startRemove failed", e);
@@ -653,33 +657,64 @@
     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);
+                }
+            });
         }
     };
 
@@ -764,6 +799,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
+                    MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
                     startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted);
                 }
             });
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 57ca552..5c60a61 100644
--- a/services/core/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/core/java/com/android/server/location/GpsLocationProvider.java
@@ -2200,14 +2200,18 @@
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         StringBuilder s = new StringBuilder();
-        s.append("  mFixInterval=").append(mFixInterval).append("\n");
-        s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append("\n");
-        s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities)).append(" (");
-        if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHED ");
+        s.append("  mFixInterval=").append(mFixInterval).append('\n');
+        s.append("  mDisableGps (battery saver mode)=").append(mDisableGps).append('\n');
+        s.append("  mEngineCapabilities=0x").append(Integer.toHexString(mEngineCapabilities));
+        s.append(" ( ");
+        if (hasCapability(GPS_CAPABILITY_SCHEDULING)) s.append("SCHEDULING ");
         if (hasCapability(GPS_CAPABILITY_MSB)) s.append("MSB ");
         if (hasCapability(GPS_CAPABILITY_MSA)) s.append("MSA ");
         if (hasCapability(GPS_CAPABILITY_SINGLE_SHOT)) s.append("SINGLE_SHOT ");
         if (hasCapability(GPS_CAPABILITY_ON_DEMAND_TIME)) s.append("ON_DEMAND_TIME ");
+        if (hasCapability(GPS_CAPABILITY_GEOFENCING)) s.append("GEOFENCING ");
+        if (hasCapability(GPS_CAPABILITY_MEASUREMENTS)) s.append("MEASUREMENTS ");
+        if (hasCapability(GPS_CAPABILITY_NAV_MESSAGES)) s.append("NAV_MESSAGES ");
         s.append(")\n");
 
         s.append(native_get_internal_state());
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 40956c1..19d8538 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -67,7 +67,7 @@
     public void addSystemProvider(SystemConditionProviderService service) {
         mSystemConditionProviders.add(service);
         service.attachBase(mContext);
-        registerService(service.asInterface(), service.getComponent(), UserHandle.USER_OWNER);
+        registerService(service.asInterface(), service.getComponent(), UserHandle.USER_SYSTEM);
     }
 
     public Iterable<SystemConditionProviderService> getSystemProviders() {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 4351798..0c884f15 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -716,7 +716,7 @@
                             final IPackageManager pm = AppGlobals.getPackageManager();
                             final int enabled = pm.getApplicationEnabledSetting(pkgName,
                                     changeUserId != UserHandle.USER_ALL ? changeUserId :
-                                    UserHandle.USER_OWNER);
+                                    UserHandle.USER_SYSTEM);
                             if (enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                                     || enabled == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
                                 cancelNotifications = false;
@@ -1420,7 +1420,7 @@
                             if (!r.isSeen()) {
                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
                                 mAppUsageStats.reportEvent(r.sbn.getPackageName(),
-                                        userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
+                                        userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM
                                                 : userId,
                                         UsageEvents.Event.USER_INTERACTION);
                                 r.setSeen();
@@ -1701,7 +1701,8 @@
         @Override
         public byte[] getBackupPayload(int user) {
             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
-            if (user != UserHandle.USER_OWNER) {
+            //TODO: http://b/22388012
+            if (user != UserHandle.USER_SYSTEM) {
                 Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
                 return null;
             }
@@ -1723,7 +1724,8 @@
                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
                 return;
             }
-            if (user != UserHandle.USER_OWNER) {
+            //TODO: http://b/22388012
+            if (user != UserHandle.USER_SYSTEM) {
                 Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
                 return;
             }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index a089518..66381f5 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -148,7 +148,8 @@
                     if (!TextUtils.isEmpty(name)) {
                         if (forRestore) {
                             try {
-                                uid = pm.getPackageUid(name, UserHandle.USER_OWNER);
+                                //TODO: http://b/22388012
+                                uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM);
                             } catch (NameNotFoundException e) {
                                 // noop
                             }
@@ -213,7 +214,8 @@
         final int N = mRecords.size();
         for (int i = 0; i < N; i++) {
             final Record r = mRecords.valueAt(i);
-            if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_OWNER) {
+            //TODO: http://b/22388012
+            if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
                 continue;
             }
             out.startTag(null, TAG_PACKAGE);
@@ -437,7 +439,8 @@
             final Record r = mRestoredWithoutUids.get(pkg);
             if (r != null) {
                 try {
-                    r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_OWNER);
+                    //TODO: http://b/22388012
+                    r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM);
                     mRestoredWithoutUids.remove(pkg);
                     mRecords.put(recordKey(r.pkg, r.uid), r);
                     updated = true;
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 57d7758..0a12d5a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -85,7 +85,7 @@
     private final Metrics mMetrics = new Metrics();
 
     private int mZenMode;
-    private int mUser = UserHandle.USER_OWNER;
+    private int mUser = UserHandle.USER_SYSTEM;
     private ZenModeConfig mConfig;
     private AudioManagerInternal mAudioManager;
     private boolean mEffectsSuppressed;
@@ -99,7 +99,7 @@
         appendDefaultScheduleRules(mDefaultConfig);
         appendDefaultEventRules(mDefaultConfig);
         mConfig = mDefaultConfig;
-        mConfigs.put(UserHandle.USER_OWNER, mConfig);
+        mConfigs.put(UserHandle.USER_SYSTEM, mConfig);
         mSettingsObserver = new SettingsObserver(mHandler);
         mSettingsObserver.observe();
         mFiltering = new ZenModeFiltering(mContext);
@@ -152,7 +152,7 @@
     }
 
     public void onUserSwitched(int user) {
-        if (mUser == user || user < UserHandle.USER_OWNER) return;
+        if (mUser == user || user < UserHandle.USER_SYSTEM) return;
         mUser = user;
         if (DEBUG) Log.d(TAG, "onUserSwitched u=" + user);
         ZenModeConfig config = mConfigs.get(user);
@@ -165,7 +165,7 @@
     }
 
     public void onUserRemoved(int user) {
-        if (user < UserHandle.USER_OWNER) return;
+        if (user < UserHandle.USER_SYSTEM) return;
         if (DEBUG) Log.d(TAG, "onUserRemoved u=" + user);
         mConfigs.remove(user);
     }
@@ -265,7 +265,8 @@
         final ZenModeConfig config = ZenModeConfig.readXml(parser, mConfigMigration);
         if (config != null) {
             if (forRestore) {
-                if (config.user != UserHandle.USER_OWNER) {
+                //TODO: http://b/22388012
+                if (config.user != UserHandle.USER_SYSTEM) {
                     return;
                 }
                 config.manualRule = null;  // don't restore the manual rule
@@ -285,7 +286,8 @@
     public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
         final int N = mConfigs.size();
         for (int i = 0; i < N; i++) {
-            if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_OWNER) {
+            //TODO: http://b/22388012
+            if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
                 continue;
             }
             mConfigs.valueAt(i).writeXml(out);
@@ -411,8 +413,7 @@
         applyRestrictions(muteNotifications, USAGE_NOTIFICATION);
 
         // call restrictions
-        final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers
-                || mEffectsSuppressed;
+        final boolean muteCalls = zen && !mConfig.allowCalls && !mConfig.allowRepeatCallers;
         applyRestrictions(muteCalls, USAGE_NOTIFICATION_RINGTONE);
 
         // alarm restrictions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 051c815..e1f3528 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);
                     }
 
@@ -4248,16 +4266,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;
@@ -4554,7 +4574,7 @@
                 if (xpResolveInfo != null && isUserEnabled(xpResolveInfo.targetUserId)) {
                     List<ResolveInfo> result = new ArrayList<ResolveInfo>(1);
                     result.add(xpResolveInfo);
-                    return filterIfNotPrimaryUser(result, userId);
+                    return filterIfNotSystemUser(result, userId);
                 }
 
                 // Check for results in the current profile.
@@ -4568,7 +4588,7 @@
                     result.add(xpResolveInfo);
                     Collections.sort(result, mResolvePrioritySorter);
                 }
-                result = filterIfNotPrimaryUser(result, userId);
+                result = filterIfNotSystemUser(result, userId);
                 if (hasWebURI(intent)) {
                     CrossProfileDomainInfo xpDomainInfo = null;
                     final UserInfo parent = getProfileParent(userId);
@@ -4597,7 +4617,7 @@
             }
             final PackageParser.Package pkg = mPackages.get(pkgName);
             if (pkg != null) {
-                return filterIfNotPrimaryUser(
+                return filterIfNotSystemUser(
                         mActivities.queryIntentForPackage(
                                 intent, resolvedType, flags, pkg.activities, userId),
                         userId);
@@ -4644,7 +4664,7 @@
             if (result == null) {
                 result = new CrossProfileDomainInfo();
                 result.resolveInfo =
-                        createForwardingResolveInfo(null, sourceUserId, parentUserId);
+                        createForwardingResolveInfo(new IntentFilter(), sourceUserId, parentUserId);
                 result.bestDomainVerificationStatus = status;
             } else {
                 result.bestDomainVerificationStatus = bestDomainVerificationStatus(status,
@@ -4684,17 +4704,17 @@
     }
 
     /**
-     * Filter out activities with primaryUserOnly flag set, when current user is not the owner.
+     * Filter out activities with systemUserOnly flag set, when current user is not System.
      *
      * @return filtered list
      */
-    private List<ResolveInfo> filterIfNotPrimaryUser(List<ResolveInfo> resolveInfos, int userId) {
-        if (userId == UserHandle.USER_OWNER) {
+    private List<ResolveInfo> filterIfNotSystemUser(List<ResolveInfo> resolveInfos, int userId) {
+        if (userId == UserHandle.USER_SYSTEM) {
             return resolveInfos;
         }
         for (int i = resolveInfos.size() - 1; i >= 0; i--) {
             ResolveInfo info = resolveInfos.get(i);
-            if ((info.activityInfo.flags & ActivityInfo.FLAG_PRIMARY_USER_ONLY) != 0) {
+            if ((info.activityInfo.flags & ActivityInfo.FLAG_SYSTEM_USER_ONLY) != 0) {
                 resolveInfos.remove(i);
             }
         }
@@ -6119,7 +6139,7 @@
             }
             // Give priority to system apps that listen for pre boot complete.
             Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
-            ArraySet<String> pkgNames = getPackageNamesForIntent(intent);
+            ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
             for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                 PackageParser.Package pkg = it.next();
                 if (pkgNames.contains(pkg.packageName)) {
@@ -6154,7 +6174,7 @@
             }
             // Give priority to apps that listen for boot complete.
             intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
-            pkgNames = getPackageNamesForIntent(intent);
+            pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
             for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
                 PackageParser.Package pkg = it.next();
                 if (pkgNames.contains(pkg.packageName)) {
@@ -6225,11 +6245,11 @@
         }
     }
 
-    private ArraySet<String> getPackageNamesForIntent(Intent intent) {
+    private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
         List<ResolveInfo> ris = null;
         try {
             ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, 0, UserHandle.USER_OWNER);
+                    intent, null, 0, userId);
         } catch (RemoteException e) {
         }
         ArraySet<String> pkgNames = new ArraySet<String>();
@@ -6262,10 +6282,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 +6381,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 +7273,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 +7900,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 +9688,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 +9716,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 +10053,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 +10350,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 +10382,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 +10393,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 +10627,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 +10934,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 +11072,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 +11084,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 +11097,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 +11192,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 +11202,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 +11428,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 +11437,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 +11454,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 +11722,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) {
@@ -11852,8 +11934,9 @@
         String pkgName = pkg.packageName;
 
         if (DEBUG_INSTALL) Slog.d(TAG, "installNewPackageLI: " + pkg);
+        // TODO: b/23350563
         final boolean dataDirExists = Environment
-                .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_OWNER, pkgName).exists();
+                .getDataUserPackageDirectory(volumeUuid, UserHandle.USER_SYSTEM, pkgName).exists();
 
         synchronized(mPackages) {
             if (mSettings.mRenamedPackages.containsKey(pkgName)) {
@@ -12200,7 +12283,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);
@@ -12252,7 +12337,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);
@@ -12501,9 +12588,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;
@@ -13727,9 +13818,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);
                 }
             }
         }
@@ -16193,8 +16289,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/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 715dd2c..61d2676 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -23,7 +23,6 @@
 import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS;
-import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED;
 import static android.os.Process.SYSTEM_UID;
 import static android.os.Process.PACKAGE_INFO_GID;
@@ -39,13 +38,10 @@
 import android.os.Build;
 import android.os.Environment;
 import android.os.FileUtils;
-import android.os.IBinder;
 import android.os.Handler;
 import android.os.Message;
 import android.os.PatternMatcher;
 import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
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 e0da33f..9ddbcca 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -773,6 +773,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 +787,7 @@
         @Override
         public void onProposedRotationChanged(int rotation) {
             if (localLOGV) Slog.v(TAG, "onProposedRotationChanged, rotation=" + rotation);
-            updateRotation(false);
+            mHandler.post(mUpdateRotationRunnable);
         }
     }
     MyOrientationListener mOrientationListener;
@@ -4455,7 +4462,7 @@
                     if (mAppsToBeHidden.isEmpty()) {
                         if (dismissKeyguard && !mKeyguardSecure) {
                             mAppsThatDismissKeyguard.add(appToken);
-                        } else {
+                        } else if (win.isDrawnLw()) {
                             mWinShowWhenLocked = win;
                             mHideLockScreen = true;
                             mForceStatusBarFromKeyguard = false;
@@ -4489,7 +4496,7 @@
                         mWinDismissingKeyguard = win;
                         mSecureDismissingKeyguard = mKeyguardSecure;
                         mForceStatusBarFromKeyguard = mShowingLockscreen && mKeyguardSecure;
-                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked) {
+                    } else if (mAppsToBeHidden.isEmpty() && showWhenLocked && win.isDrawnLw()) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
                                 "Setting mHideLockScreen to true by win " + win);
                         mHideLockScreen = true;
diff --git a/services/core/java/com/android/server/policy/StatusBarController.java b/services/core/java/com/android/server/policy/StatusBarController.java
index da23f45..b935f5a 100644
--- a/services/core/java/com/android/server/policy/StatusBarController.java
+++ b/services/core/java/com/android/server/policy/StatusBarController.java
@@ -72,7 +72,9 @@
                         if (statusbar != null) {
                             long startTime = calculateStatusBarTransitionStartTime(openAnimation,
                                     closeAnimation);
-                            statusbar.appTransitionStarting(startTime, TRANSITION_DURATION);
+                            long duration = closeAnimation != null || openAnimation != null
+                                    ? TRANSITION_DURATION : 0;
+                            statusbar.appTransitionStarting(startTime, duration);
                         }
                     } catch (RemoteException e) {
                         Slog.e(mTag, "RemoteException when app transition is starting", e);
diff --git a/services/core/java/com/android/server/policy/WindowOrientationListener.java b/services/core/java/com/android/server/policy/WindowOrientationListener.java
index c71b48f..9916223 100644
--- a/services/core/java/com/android/server/policy/WindowOrientationListener.java
+++ b/services/core/java/com/android/server/policy/WindowOrientationListener.java
@@ -24,10 +24,12 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Slog;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * A special helper class used by the WindowManager
@@ -52,8 +54,9 @@
     private SensorManager mSensorManager;
     private boolean mEnabled;
     private int mRate;
+    private String mSensorType;
     private Sensor mSensor;
-    private SensorEventListenerImpl mSensorEventListener;
+    private OrientationJudge mOrientationJudge;
     private int mCurrentRotation = -1;
 
     private final Object mLock = new Object();
@@ -67,7 +70,7 @@
     public WindowOrientationListener(Context context, Handler handler) {
         this(context, handler, SensorManager.SENSOR_DELAY_UI);
     }
-    
+
     /**
      * Creates a new WindowOrientationListener.
      * 
@@ -84,11 +87,31 @@
         mHandler = handler;
         mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
         mRate = rate;
-        mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
-                ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
-        if (mSensor != null) {
-            // Create listener only if sensors do exist
-            mSensorEventListener = new SensorEventListenerImpl(context);
+
+        mSensorType = context.getResources().getString(
+                com.android.internal.R.string.config_orientationSensorType);
+        if (!TextUtils.isEmpty(mSensorType)) {
+            List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+            final int N = sensors.size();
+            for (int i = 0; i < N; i++) {
+                Sensor sensor = sensors.get(i);
+                if (mSensorType.equals(sensor.getStringType())) {
+                    mSensor = sensor;
+                    break;
+                }
+            }
+            if (mSensor != null) {
+                mOrientationJudge = new OrientationSensorJudge();
+            }
+        }
+
+        if (mOrientationJudge == null) {
+            mSensor = mSensorManager.getDefaultSensor(USE_GRAVITY_SENSOR
+                    ? Sensor.TYPE_GRAVITY : Sensor.TYPE_ACCELEROMETER);
+            if (mSensor != null) {
+                // Create listener only if sensors do exist
+                mOrientationJudge = new AccelSensorJudge(context);
+            }
         }
     }
 
@@ -106,8 +129,8 @@
                 if (LOG) {
                     Slog.d(TAG, "WindowOrientationListener enabled");
                 }
-                mSensorEventListener.resetLocked();
-                mSensorManager.registerListener(mSensorEventListener, mSensor, mRate, mHandler);
+                mOrientationJudge.resetLocked();
+                mSensorManager.registerListener(mOrientationJudge, mSensor, mRate, mHandler);
                 mEnabled = true;
             }
         }
@@ -126,7 +149,7 @@
                 if (LOG) {
                     Slog.d(TAG, "WindowOrientationListener disabled");
                 }
-                mSensorManager.unregisterListener(mSensorEventListener);
+                mSensorManager.unregisterListener(mOrientationJudge);
                 mEnabled = false;
             }
         }
@@ -134,8 +157,8 @@
 
     public void onTouchStart() {
         synchronized (mLock) {
-            if (mSensorEventListener != null) {
-                mSensorEventListener.onTouchStartLocked();
+            if (mOrientationJudge != null) {
+                mOrientationJudge.onTouchStartLocked();
             }
         }
     }
@@ -144,8 +167,8 @@
         long whenElapsedNanos = SystemClock.elapsedRealtimeNanos();
 
         synchronized (mLock) {
-            if (mSensorEventListener != null) {
-                mSensorEventListener.onTouchEndLocked(whenElapsedNanos);
+            if (mOrientationJudge != null) {
+                mOrientationJudge.onTouchEndLocked(whenElapsedNanos);
             }
         }
     }
@@ -172,7 +195,7 @@
     public int getProposedRotation() {
         synchronized (mLock) {
             if (mEnabled) {
-                return mSensorEventListener.getProposedRotationLocked();
+                return mOrientationJudge.getProposedRotationLocked();
             }
             return -1;
         }
@@ -194,6 +217,8 @@
      * It is called each time the orientation determination transitions from being
      * uncertain to being certain again, even if it is the same orientation as before.
      *
+     * This should only be called on the Handler thread.
+     *
      * @param rotation The new orientation of the device, one of the Surface.ROTATION_* constants.
      * @see android.view.Surface
      */
@@ -205,15 +230,77 @@
             prefix += "  ";
             pw.println(prefix + "mEnabled=" + mEnabled);
             pw.println(prefix + "mCurrentRotation=" + mCurrentRotation);
+            pw.println(prefix + "mSensorType=" + mSensorType);
             pw.println(prefix + "mSensor=" + mSensor);
             pw.println(prefix + "mRate=" + mRate);
 
-            if (mSensorEventListener != null) {
-                mSensorEventListener.dumpLocked(pw, prefix);
+            if (mOrientationJudge != null) {
+                mOrientationJudge.dumpLocked(pw, prefix);
             }
         }
     }
 
+    abstract class OrientationJudge implements SensorEventListener {
+        // Number of nanoseconds per millisecond.
+        protected static final long NANOS_PER_MS = 1000000;
+
+        // Number of milliseconds per nano second.
+        protected static final float MILLIS_PER_NANO = 0.000001f;
+
+        // The minimum amount of time that must have elapsed since the screen was last touched
+        // before the proposed rotation can change.
+        protected static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS =
+                500 * NANOS_PER_MS;
+
+        /**
+         * Gets the proposed rotation.
+         *
+         * This method only returns a rotation if the orientation listener is certain
+         * of its proposal.  If the rotation is indeterminate, returns -1.
+         *
+         * Should only be called when holding WindowOrientationListener lock.
+         *
+         * @return The proposed rotation, or -1 if unknown.
+         */
+        public abstract int getProposedRotationLocked();
+
+        /**
+         * Notifies the orientation judge that the screen is being touched.
+         *
+         * Should only be called when holding WindowOrientationListener lock.
+         */
+        public abstract void onTouchStartLocked();
+
+        /**
+         * Notifies the orientation judge that the screen is no longer being touched.
+         *
+         * Should only be called when holding WindowOrientationListener lock.
+         *
+         * @param whenElapsedNanos Given in the elapsed realtime nanos time base.
+         */
+        public abstract void onTouchEndLocked(long whenElapsedNanos);
+
+        /**
+         * Resets the state of the judge.
+         *
+         * Should only be called when holding WindowOrientationListener lock.
+         */
+        public abstract void resetLocked();
+
+        /**
+         * Dumps internal state of the orientation judge.
+         *
+         * Should only be called when holding WindowOrientationListener lock.
+         */
+        public abstract void dumpLocked(PrintWriter pw, String prefix);
+
+        @Override
+        public abstract void onAccuracyChanged(Sensor sensor, int accuracy);
+
+        @Override
+        public abstract void onSensorChanged(SensorEvent event);
+    }
+
     /**
      * This class filters the raw accelerometer data and tries to detect actual changes in
      * orientation. This is a very ill-defined problem so there are a lot of tweakable parameters,
@@ -252,13 +339,10 @@
      * See http://en.wikipedia.org/wiki/Low-pass_filter#Discrete-time_realization for
      * signal processing background.
      */
-    final class SensorEventListenerImpl implements SensorEventListener {
+    final class AccelSensorJudge extends OrientationJudge {
         // We work with all angles in degrees in this class.
         private static final float RADIANS_TO_DEGREES = (float) (180 / Math.PI);
 
-        // Number of nanoseconds per millisecond.
-        private static final long NANOS_PER_MS = 1000000;
-
         // Indices into SensorEvent.values for the accelerometer sensor.
         private static final int ACCELEROMETER_DATA_X = 0;
         private static final int ACCELEROMETER_DATA_Y = 1;
@@ -286,11 +370,6 @@
         private static final long PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS =
                 500 * NANOS_PER_MS;
 
-        // The minimum amount of time that must have elapsed since the screen was last touched
-        // before the proposed rotation can change.
-        private static final long PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS =
-                500 * NANOS_PER_MS;
-
         // If the tilt angle remains greater than the specified angle for a minimum of
         // the specified time, then the device is deemed to be lying flat
         // (just chillin' on a table).
@@ -434,7 +513,7 @@
         private long[] mTiltHistoryTimestampNanos = new long[TILT_HISTORY_SIZE];
         private int mTiltHistoryIndex;
 
-        public SensorEventListenerImpl(Context context) {
+        public AccelSensorJudge(Context context) {
             // Load tilt tolerance configuration.
             int[] tiltTolerance = context.getResources().getIntArray(
                     com.android.internal.R.array.config_autoRotationTiltTolerance);
@@ -455,11 +534,15 @@
             }
         }
 
+        @Override
         public int getProposedRotationLocked() {
             return mProposedRotation;
         }
 
+        @Override
         public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.println(prefix + "AccelSensorJudge");
+            prefix += "  ";
             pw.println(prefix + "mProposedRotation=" + mProposedRotation);
             pw.println(prefix + "mPredictedRotation=" + mPredictedRotation);
             pw.println(prefix + "mLastFilteredX=" + mLastFilteredX);
@@ -689,6 +772,33 @@
             }
         }
 
+        @Override
+        public void onTouchStartLocked() {
+            mTouched = true;
+        }
+
+        @Override
+        public void onTouchEndLocked(long whenElapsedNanos) {
+            mTouched = false;
+            mTouchEndedTimestampNanos = whenElapsedNanos;
+        }
+
+        @Override
+        public void resetLocked() {
+            mLastFilteredTimestampNanos = Long.MIN_VALUE;
+            mProposedRotation = -1;
+            mFlatTimestampNanos = Long.MIN_VALUE;
+            mFlat = false;
+            mSwingTimestampNanos = Long.MIN_VALUE;
+            mSwinging = false;
+            mAccelerationTimestampNanos = Long.MIN_VALUE;
+            mAccelerating = false;
+            mOverhead = false;
+            clearPredictedRotationLocked();
+            clearTiltHistoryLocked();
+        }
+
+
         /**
          * Returns true if the tilt angle is acceptable for a given predicted rotation.
          */
@@ -787,20 +897,6 @@
             return true;
         }
 
-        private void resetLocked() {
-            mLastFilteredTimestampNanos = Long.MIN_VALUE;
-            mProposedRotation = -1;
-            mFlatTimestampNanos = Long.MIN_VALUE;
-            mFlat = false;
-            mSwingTimestampNanos = Long.MIN_VALUE;
-            mSwinging = false;
-            mAccelerationTimestampNanos = Long.MIN_VALUE;
-            mAccelerating = false;
-            mOverhead = false;
-            clearPredictedRotationLocked();
-            clearTiltHistoryLocked();
-        }
-
         private void clearPredictedRotationLocked() {
             mPredictedRotation = -1;
             mPredictedRotationTimestampNanos = Long.MIN_VALUE;
@@ -869,14 +965,147 @@
         private float remainingMS(long now, long until) {
             return now >= until ? 0 : (until - now) * 0.000001f;
         }
+    }
 
-        private void onTouchStartLocked() {
-            mTouched = true;
+    final class OrientationSensorJudge extends OrientationJudge {
+        private boolean mTouching;
+        private long mTouchEndedTimestampNanos = Long.MIN_VALUE;
+        private int mProposedRotation = -1;
+        private int mDesiredRotation = -1;
+        private boolean mRotationEvaluationScheduled;
+
+        @Override
+        public int getProposedRotationLocked() {
+            return mProposedRotation;
         }
 
-        private void onTouchEndLocked(long whenElapsedNanos) {
-            mTouched = false;
+        @Override
+        public void onTouchStartLocked() {
+            mTouching = true;
+        }
+
+        @Override
+        public void onTouchEndLocked(long whenElapsedNanos) {
+            mTouching = false;
             mTouchEndedTimestampNanos = whenElapsedNanos;
+            if (mDesiredRotation != mProposedRotation) {
+                final long now = SystemClock.elapsedRealtimeNanos();
+                scheduleRotationEvaluationIfNecessaryLocked(now);
+            }
         }
+
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            int newRotation;
+            synchronized (mLock) {
+                mDesiredRotation = (int) event.values[0];
+                newRotation = evaluateRotationChangeLocked();
+            }
+            if (newRotation >=0) {
+                onProposedRotationChanged(newRotation);
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) { }
+
+        @Override
+        public void dumpLocked(PrintWriter pw, String prefix) {
+            pw.println(prefix + "OrientationSensorJudge");
+            prefix += "  ";
+            pw.println(prefix + "mDesiredRotation=" + mDesiredRotation);
+            pw.println(prefix + "mProposedRotation=" + mProposedRotation);
+            pw.println(prefix + "mTouching=" + mTouching);
+            pw.println(prefix + "mTouchEndedTimestampNanos=" + mTouchEndedTimestampNanos);
+        }
+
+        @Override
+        public void resetLocked() {
+            mProposedRotation = -1;
+            mDesiredRotation = -1;
+            mTouching = false;
+            mTouchEndedTimestampNanos = Long.MIN_VALUE;
+            unscheduleRotationEvaluationLocked();
+        }
+
+        public int evaluateRotationChangeLocked() {
+            unscheduleRotationEvaluationLocked();
+            if (mDesiredRotation == mProposedRotation) {
+                return -1;
+            }
+            final long now = SystemClock.elapsedRealtimeNanos();
+            if (isDesiredRotationAcceptableLocked(now)) {
+                mProposedRotation = mDesiredRotation;
+                return mProposedRotation;
+            } else {
+                scheduleRotationEvaluationIfNecessaryLocked(now);
+            }
+            return -1;
+        }
+
+        private boolean isDesiredRotationAcceptableLocked(long now) {
+            if (mTouching) {
+                return false;
+            }
+            if (now < mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS) {
+                return false;
+            }
+            return true;
+        }
+
+        private void scheduleRotationEvaluationIfNecessaryLocked(long now) {
+            if (mRotationEvaluationScheduled || mDesiredRotation == mProposedRotation) {
+                if (LOG) {
+                    Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+                            "ignoring, an evaluation is already scheduled or is unnecessary.");
+                }
+                return;
+            }
+            if (mTouching) {
+                if (LOG) {
+                    Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+                            "ignoring, user is still touching the screen.");
+                }
+                return;
+            }
+            long timeOfNextPossibleRotationNanos =
+                mTouchEndedTimestampNanos + PROPOSAL_MIN_TIME_SINCE_TOUCH_END_NANOS;
+            if (now >= timeOfNextPossibleRotationNanos) {
+                if (LOG) {
+                    Slog.d(TAG, "scheduleRotationEvaluationLocked: " +
+                            "ignoring, already past the next possible time of rotation.");
+                }
+                return;
+            }
+            // Use a delay instead of an absolute time since handlers are in uptime millis and we
+            // use elapsed realtime.
+            final long delayMs =
+                    (long) Math.ceil((timeOfNextPossibleRotationNanos - now) * MILLIS_PER_NANO);
+            mHandler.postDelayed(mRotationEvaluator, delayMs);
+            mRotationEvaluationScheduled = true;
+        }
+
+        private void unscheduleRotationEvaluationLocked() {
+            if (!mRotationEvaluationScheduled) {
+                return;
+            }
+            mHandler.removeCallbacks(mRotationEvaluator);
+            mRotationEvaluationScheduled = false;
+        }
+
+        private Runnable mRotationEvaluator = new Runnable() {
+            @Override
+            public void run() {
+                int newRotation;
+                synchronized (mLock) {
+                    mRotationEvaluationScheduled = false;
+                    newRotation = evaluateRotationChangeLocked();
+                }
+                if (newRotation >= 0) {
+                    onProposedRotationChanged(newRotation);
+                }
+            }
+        };
     }
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 130815e..5d01931 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -28,4 +28,5 @@
     void showScreenPinningRequest();
     void showAssistDisclosure();
     void startAssist(Bundle args);
+    void onCameraLaunchGestureDetected();
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 8663254..87dc6c4 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -176,6 +176,16 @@
                 }
             }
         }
+
+        @Override
+        public void onCameraLaunchGestureDetected() {
+            if (mBar != null) {
+                try {
+                    mBar.onCameraLaunchGestureDetected();
+                } catch (RemoteException e) {
+                }
+            }
+        }
     };
 
     // ================================================================================
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index b9e8851..f9d29ac 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -19,6 +19,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.content.PackageMonitor;
 import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
 import com.android.server.SystemService;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -59,6 +60,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
 import android.util.Xml;
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
@@ -96,16 +98,15 @@
     private static final int MSG_UNREGISTER_LISTENER = 2;
     private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
     private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
-    private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
     private static final int MSG_KEYGUARD_SHOWING_CHANGED = 6;
     private static final int MSG_START_USER = 7;
     private static final int MSG_CLEANUP_USER = 8;
     private static final int MSG_SWITCH_USER = 9;
 
-    private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
-    private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+    private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
+    private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
     private final Receiver mReceiver = new Receiver();
-    private final SparseBooleanArray mUserHasAuthenticated = new SparseBooleanArray();
+
     /* package */ final TrustArchive mArchive = new TrustArchive();
     private final Context mContext;
     private final LockPatternUtils mLockPatternUtils;
@@ -118,9 +119,6 @@
     @GuardedBy("mDeviceLockedForUser")
     private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
 
-    @GuardedBy("mUserHasAuthenticatedSinceBoot")
-    private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
-
     private boolean mTrustAgentsCanRun = false;
     private int mCurrentUser = UserHandle.USER_SYSTEM;
 
@@ -146,6 +144,7 @@
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
             mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
             mReceiver.register(mContext);
+            mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             mTrustAgentsCanRun = true;
             refreshAgentList(UserHandle.USER_ALL);
@@ -230,7 +229,7 @@
             if (!userInfo.supportsSwitchToByUser()) continue;
             if (!mActivityManager.isUserRunning(userInfo.id)) continue;
             if (!lockPatternUtils.isSecure(userInfo.id)) continue;
-            if (!getUserHasAuthenticated(userInfo.id)) continue;
+            if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue;
             DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
             int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
             final boolean disableTrustAgents =
@@ -509,7 +508,7 @@
     // Agent dispatch and aggregation
 
     private boolean aggregateIsTrusted(int userId) {
-        if (!getUserHasAuthenticated(userId)) {
+        if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
             return false;
         }
         for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -524,7 +523,7 @@
     }
 
     private boolean aggregateIsTrustManaged(int userId) {
-        if (!getUserHasAuthenticated(userId)) {
+        if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
             return false;
         }
         for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -545,54 +544,6 @@
                 info.agent.onUnlockAttempt(successful);
             }
         }
-
-        if (successful) {
-            updateUserHasAuthenticated(userId);
-        }
-    }
-
-    private void updateUserHasAuthenticated(int userId) {
-        boolean changed = setUserHasAuthenticated(userId);
-        if (changed) {
-            refreshAgentList(userId);
-        }
-    }
-
-    private boolean getUserHasAuthenticated(int userId) {
-        return mUserHasAuthenticated.get(userId);
-    }
-
-    /**
-     * @return whether the value has changed
-     */
-    private boolean setUserHasAuthenticated(int userId) {
-        if (!mUserHasAuthenticated.get(userId)) {
-            mUserHasAuthenticated.put(userId, true);
-            synchronized (mUserHasAuthenticatedSinceBoot) {
-                mUserHasAuthenticatedSinceBoot.put(userId, true);
-            }
-            return true;
-        }
-        return false;
-    }
-
-    private void clearUserHasAuthenticated(int userId) {
-        if (userId == UserHandle.USER_ALL) {
-            mUserHasAuthenticated.clear();
-        } else {
-            mUserHasAuthenticated.put(userId, false);
-        }
-    }
-
-    private boolean getUserHasAuthenticatedSinceBoot(int userId) {
-        synchronized (mUserHasAuthenticatedSinceBoot) {
-            return mUserHasAuthenticatedSinceBoot.get(userId);
-        }
-    }
-
-    private void requireCredentialEntry(int userId) {
-        clearUserHasAuthenticated(userId);
-        refreshAgentList(userId);
     }
 
     // Listeners
@@ -681,17 +632,6 @@
         }
 
         @Override
-        public void reportRequireCredentialEntry(int userId) throws RemoteException {
-            enforceReportPermission();
-            if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_SYSTEM) {
-                mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget();
-            } else {
-                throw new IllegalArgumentException(
-                        "userId must be an explicit user id or USER_ALL");
-            }
-        }
-
-        @Override
         public void reportKeyguardShowingChanged() throws RemoteException {
             enforceReportPermission();
             // coalesce refresh messages.
@@ -734,18 +674,6 @@
             }
         }
 
-        @Override
-        public boolean hasUserAuthenticatedSinceBoot(int userId) throws RemoteException {
-            mContext.enforceCallingOrSelfPermission(
-                    Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, null);
-            long token = Binder.clearCallingIdentity();
-            try {
-                return getUserHasAuthenticatedSinceBoot(userId);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
         private void enforceReportPermission() {
             mContext.enforceCallingOrSelfPermission(
                     Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -794,9 +722,8 @@
             fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
             fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
             fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
-            fout.print(", hasAuthenticated=" + dumpBool(getUserHasAuthenticated(user.id)));
-            fout.print(", hasAuthenticatedSinceBoot="
-                    + dumpBool(getUserHasAuthenticatedSinceBoot(user.id)));
+            fout.print(", strongAuthRequired=" + dumpHex(
+                    mStrongAuthTracker.getStrongAuthForUser(user.id)));
             fout.println();
             fout.println("   Enabled agents:");
             boolean duplicateSimpleNames = false;
@@ -831,6 +758,10 @@
         private String dumpBool(boolean b) {
             return b ? "1" : "0";
         }
+
+        private String dumpHex(int i) {
+            return "0x" + Integer.toHexString(i);
+        }
     };
 
     private int resolveProfileParent(int userId) {
@@ -864,9 +795,6 @@
                     // This is also called when the security mode of a user changes.
                     refreshDeviceLockedForUser(UserHandle.USER_ALL);
                     break;
-                case MSG_REQUIRE_CREDENTIAL_ENTRY:
-                    requireCredentialEntry(msg.arg1);
-                    break;
                 case MSG_KEYGUARD_SHOWING_CHANGED:
                     refreshDeviceLockedForUser(mCurrentUser);
                     break;
@@ -900,6 +828,13 @@
         }
     };
 
+    private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker() {
+        @Override
+        public void onStrongAuthRequiredChanged(int userId) {
+            refreshAgentList(userId);
+        }
+    };
+
     private class Receiver extends BroadcastReceiver {
 
         @Override
@@ -908,8 +843,6 @@
             if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
                 refreshAgentList(getSendingUserId());
                 updateDevicePolicyFeatures();
-            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                updateUserHasAuthenticated(getSendingUserId());
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 int userId = getUserId(intent);
                 if (userId > 0) {
@@ -918,7 +851,6 @@
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 int userId = getUserId(intent);
                 if (userId > 0) {
-                    mUserHasAuthenticated.delete(userId);
                     synchronized (mUserIsTrusted) {
                         mUserIsTrusted.delete(userId);
                     }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index d1145d0..de7c07e 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -870,10 +870,10 @@
     }
 
     private Animation createAspectScaledThumbnailEnterNonFullscreenAnimationLocked(
-            Rect containingFrame, @Nullable Rect surfaceInsets, int taskId) {
+            Rect frame, @Nullable Rect surfaceInsets, int taskId) {
         getNextAppTransitionStartRect(taskId, mTmpStartRect);
-        float width = containingFrame.width();
-        float height = containingFrame.height();
+        float width = frame.width();
+        float height = frame.height();
         float scaleWidth = mTmpStartRect.width() / width;
         float scaleHeight = mTmpStartRect.height() / height;
         AnimationSet set = new AnimationSet(true);
@@ -886,9 +886,9 @@
         ScaleAnimation scale = new ScaleAnimation(scaleWidth, 1, scaleHeight, 1,
                 (width + surfaceInsetsHorizontal) / 2, (height + surfaceInsetsVertical) / 2);
         int fromX = mTmpStartRect.left + mTmpStartRect.width() / 2
-                - (containingFrame.left + containingFrame.width() / 2);
+                - (frame.left + frame.width() / 2);
         int fromY = mTmpStartRect.top + mTmpStartRect.height() / 2
-                - (containingFrame.top + containingFrame.height() / 2);
+                - (frame.top + frame.height() / 2);
         TranslateAnimation translation = new TranslateAnimation(fromX, 0, fromY, 0);
         set.addAnimation(scale);
         set.addAnimation(translation);
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 222945c..e87dcde 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 import com.android.server.input.InputApplicationHandle;
 import com.android.server.input.InputWindowHandle;
 import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
@@ -413,7 +414,7 @@
                 continue;
             }
 
-            child.getTaskBounds(mTmpRect);
+            child.getTaskBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
             if (!mTmpRect.contains(x, y)) {
                 // outside of this window's activity stack == don't tell about drags
                 continue;
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 65f26c1..b3244ff 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
 import android.os.RemoteException;
@@ -177,7 +178,7 @@
         if (modal && child.mAppToken != null) {
             // Limit the outer touch to the activity stack region.
             flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-            child.getTaskBounds(mTmpRect);
+            child.getTaskBounds(mTmpRect, BOUNDS_FOR_TOUCH);
             inputWindowHandle.touchableRegion.set(mTmpRect);
         } else {
             // Not modal or full screen modal
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index b871d7f..d0962f4 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -98,6 +99,8 @@
     private static final int WALLPAPER_DRAW_TIMEOUT = 2;
     private int mWallpaperDrawState = WALLPAPER_DRAW_NORMAL;
 
+    private final FindWallpaperTargetResult mFindResults = new FindWallpaperTargetResult();
+
     public WallpaperController(WindowManagerService service) {
         mService = service;
     }
@@ -466,39 +469,24 @@
         }
     }
 
-    boolean adjustWallpaperWindows() {
-        mService.mInnerFields.mWallpaperMayChange = false;
-        boolean targetChanged = false;
-
-        // TODO(multidisplay): Wallpapers on main screen only.
-        final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
-        final int dw = displayInfo.logicalWidth;
-        final int dh = displayInfo.logicalHeight;
+    private void findWallpaperTarget(WindowList windows, FindWallpaperTargetResult result) {
 
         final WindowAnimator winAnimator = mService.mAnimator;
-
-        // First find top-most window that has asked to be on top of the
-        // wallpaper; all wallpapers go behind it.
-        final WindowList windows = mService.getDefaultWindowListLocked();
-        int N = windows.size();
+        result.reset();
         WindowState w = null;
-        WindowState foundW = null;
-        int foundI = 0;
-        WindowState topCurW = null;
-        int topCurI = 0;
         int windowDetachedI = -1;
-        int i = N;
-        while (i > 0) {
-            i--;
+        boolean resetTopWallpaper = false;
+        boolean inFreeformSpace = false;
+        for (int i = windows.size() - 1; i >= 0; i--) {
             w = windows.get(i);
             if ((w.mAttrs.type == TYPE_WALLPAPER)) {
-                if (topCurW == null) {
-                    topCurW = w;
-                    topCurI = i;
+                if (result.topWallpaper == null || resetTopWallpaper) {
+                    result.setTopWallpaper(w, i);
+                    resetTopWallpaper = false;
                 }
                 continue;
             }
-            topCurW = null;
+            resetTopWallpaper = true;
             if (w != winAnimator.mWindowDetachedWallpaper && w.mAppToken != null) {
                 // If this window's app token is hidden and not animating,
                 // it is of no interest to us.
@@ -511,23 +499,24 @@
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Win #" + i + " " + w + ": isOnScreen="
                     + w.isOnScreen() + " mDrawState=" + w.mWinAnimator.mDrawState);
 
-            // If the app is executing an animation because the keyguard is going away, keep the
-            // wallpaper during the animation so it doesn't flicker out.
-            final boolean hasWallpaper = (w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0
-                    || (w.mAppToken != null
-                    && w.mWinAnimator.mKeyguardGoingAwayAnimation);
+            if (!inFreeformSpace) {
+                TaskStack stack = w.getStack();
+                inFreeformSpace = stack != null && stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+            }
+
+            // If the app is executing an animation because the keyguard is going away,
+            // keep the wallpaper during the animation so it doesn't flicker out.
+            final boolean hasWallpaper = (w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0
+                    || (w.mAppToken != null && w.mWinAnimator.mKeyguardGoingAwayAnimation);
             if (hasWallpaper && w.isOnScreen()
                     && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
-                if (DEBUG_WALLPAPER) Slog.v(TAG,
-                        "Found wallpaper target: #" + i + "=" + w);
-                foundW = w;
-                foundI = i;
+                if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
+                result.setWallpaperTarget(w, i);
                 if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
-                    // The current wallpaper target is animating, so we'll
-                    // look behind it for another possible target and figure
-                    // out what is going on below.
-                    if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w
-                            + ": token animating, looking behind.");
+                    // The current wallpaper target is animating, so we'll look behind it for
+                    // another possible target and figure out what is going on later.
+                    if (DEBUG_WALLPAPER) Slog.v(TAG,
+                            "Win " + w + ": token animating, looking behind.");
                     continue;
                 }
                 break;
@@ -536,76 +525,78 @@
             }
         }
 
-        if (foundW == null && windowDetachedI >= 0) {
+        if (result.wallpaperTarget == null && windowDetachedI >= 0) {
             if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                    "Found animating detached wallpaper activity: #" + i + "=" + w);
-            foundW = w;
-            foundI = windowDetachedI;
+                    "Found animating detached wallpaper activity: #" + windowDetachedI + "=" + w);
+            result.setWallpaperTarget(w, windowDetachedI);
         }
+        if (result.wallpaperTarget == null && inFreeformSpace) {
+            // In freeform mode we set the wallpaper as its own target, so we don't need an
+            // additional window to make it visible.
+            result.setWallpaperTarget(result.topWallpaper, result.topWallpaperIndex);
+        }
+    }
 
-        if (mWallpaperTarget != foundW
-                && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != foundW)) {
-            if (DEBUG_WALLPAPER_LIGHT) {
-                Slog.v(TAG, "New wallpaper target: " + foundW
-                        + " oldTarget: " + mWallpaperTarget);
-            }
+    private boolean updateWallpaperWindowsTarget(
+            WindowList windows, FindWallpaperTargetResult result) {
+
+        boolean targetChanged = false;
+        WindowState wallpaperTarget = result.wallpaperTarget;
+        int wallpaperTargetIndex = result.wallpaperTargetIndex;
+
+        if (mWallpaperTarget != wallpaperTarget
+                && (mLowerWallpaperTarget == null || mLowerWallpaperTarget != wallpaperTarget)) {
+            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                    "New wallpaper target: " + wallpaperTarget + " oldTarget: " + mWallpaperTarget);
 
             mLowerWallpaperTarget = null;
             mUpperWallpaperTarget = null;
 
             WindowState oldW = mWallpaperTarget;
-            mWallpaperTarget = foundW;
+            mWallpaperTarget = wallpaperTarget;
             targetChanged = true;
 
-            // Now what is happening...  if the current and new targets are
-            // animating, then we are in our super special mode!
-            if (foundW != null && oldW != null) {
+            // Now what is happening...  if the current and new targets are animating,
+            // then we are in our super special mode!
+            if (wallpaperTarget != null && oldW != null) {
                 boolean oldAnim = oldW.isAnimatingLw();
-                boolean foundAnim = foundW.isAnimatingLw();
-                if (DEBUG_WALLPAPER_LIGHT) {
-                    Slog.v(TAG, "New animation: " + foundAnim
-                            + " old animation: " + oldAnim);
-                }
+                boolean foundAnim = wallpaperTarget.isAnimatingLw();
+                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                        "New animation: " + foundAnim + " old animation: " + oldAnim);
                 if (foundAnim && oldAnim) {
                     int oldI = windows.indexOf(oldW);
-                    if (DEBUG_WALLPAPER_LIGHT) {
-                        Slog.v(TAG, "New i: " + foundI + " old i: " + oldI);
-                    }
+                    if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                            "New i: " + wallpaperTargetIndex + " old i: " + oldI);
                     if (oldI >= 0) {
-                        if (DEBUG_WALLPAPER_LIGHT) {
-                            Slog.v(TAG, "Animating wallpapers: old#" + oldI
-                                    + "=" + oldW + "; new#" + foundI
-                                    + "=" + foundW);
-                        }
+                        if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                                "Animating wallpapers: old#" + oldI + "=" + oldW + "; new#"
+                                + wallpaperTargetIndex + "=" + wallpaperTarget);
 
                         // Set the new target correctly.
-                        if (foundW.mAppToken != null && foundW.mAppToken.hiddenRequested) {
-                            if (DEBUG_WALLPAPER_LIGHT) {
-                                Slog.v(TAG, "Old wallpaper still the target.");
-                            }
+                        if (wallpaperTarget.mAppToken != null
+                                && wallpaperTarget.mAppToken.hiddenRequested) {
+                            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                                    "Old wallpaper still the target.");
                             mWallpaperTarget = oldW;
-                            foundW = oldW;
-                            foundI = oldI;
+                            wallpaperTarget = oldW;
+                            wallpaperTargetIndex = oldI;
                         }
-                        // Now set the upper and lower wallpaper targets
-                        // correctly, and make sure that we are positioning
-                        // the wallpaper below the lower.
-                        else if (foundI > oldI) {
+                        // Now set the upper and lower wallpaper targets correctly,
+                        // and make sure that we are positioning the wallpaper below the lower.
+                        else if (wallpaperTargetIndex > oldI) {
                             // The new target is on top of the old one.
-                            if (DEBUG_WALLPAPER_LIGHT) {
-                                Slog.v(TAG, "Found target above old target.");
-                            }
-                            mUpperWallpaperTarget = foundW;
+                            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                                    "Found target above old target.");
+                            mUpperWallpaperTarget = wallpaperTarget;
                             mLowerWallpaperTarget = oldW;
-                            foundW = oldW;
-                            foundI = oldI;
+                            wallpaperTarget = oldW;
+                            wallpaperTargetIndex = oldI;
                         } else {
                             // The new target is below the old one.
-                            if (DEBUG_WALLPAPER_LIGHT) {
-                                Slog.v(TAG, "Found target below old target.");
-                            }
+                            if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
+                                    "Found target below old target.");
                             mUpperWallpaperTarget = oldW;
-                            mLowerWallpaperTarget = foundW;
+                            mLowerWallpaperTarget = wallpaperTarget;
                         }
                     }
                 }
@@ -614,29 +605,36 @@
         } else if (mLowerWallpaperTarget != null) {
             // Is it time to stop animating?
             if (!mLowerWallpaperTarget.isAnimatingLw() || !mUpperWallpaperTarget.isAnimatingLw()) {
-                if (DEBUG_WALLPAPER_LIGHT) {
-                    Slog.v(TAG, "No longer animating wallpaper targets!");
-                }
+                if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG, "No longer animating wallpaper targets!");
                 mLowerWallpaperTarget = null;
                 mUpperWallpaperTarget = null;
-                mWallpaperTarget = foundW;
+                mWallpaperTarget = wallpaperTarget;
                 targetChanged = true;
             }
         }
 
-        boolean visible = foundW != null;
+        result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+        return targetChanged;
+    }
+
+    boolean updateWallpaperWindowsTargetByLayer(
+            WindowList windows, FindWallpaperTargetResult result) {
+
+        WindowState wallpaperTarget = result.wallpaperTarget;
+        int wallpaperTargetIndex = result.wallpaperTargetIndex;
+        boolean visible = wallpaperTarget != null;
+
         if (visible) {
-            // The window is visible to the compositor...  but is it visible
-            // to the user?  That is what the wallpaper cares about.
-            visible = isWallpaperVisible(foundW);
+            // The window is visible to the compositor...but is it visible to the user?
+            // That is what the wallpaper cares about.
+            visible = isWallpaperVisible(wallpaperTarget);
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Wallpaper visibility: " + visible);
 
-            // If the wallpaper target is animating, we may need to copy
-            // its layer adjustment.  Only do this if we are not transfering
-            // between two wallpaper targets.
+            // If the wallpaper target is animating, we may need to copy its layer adjustment.
+            // Only do this if we are not transferring between two wallpaper targets.
             mWallpaperAnimLayerAdjustment =
-                    (mLowerWallpaperTarget == null && foundW.mAppToken != null)
-                            ? foundW.mAppToken.mAppAnimator.animLayerAdjustment : 0;
+                    (mLowerWallpaperTarget == null && wallpaperTarget.mAppToken != null)
+                            ? wallpaperTarget.mAppToken.mAppAnimator.animLayerAdjustment : 0;
 
             final int maxLayer = (mService.mPolicy.getMaxWallpaperLayer() * TYPE_LAYER_MULTIPLIER)
                     + TYPE_LAYER_OFFSET;
@@ -645,52 +643,37 @@
             // need to be sure to also be behind any of its attached windows,
             // AND any starting window associated with it, AND below the
             // maximum layer the policy allows for wallpapers.
-            while (foundI > 0) {
-                WindowState wb = windows.get(foundI - 1);
+            while (wallpaperTargetIndex > 0) {
+                WindowState wb = windows.get(wallpaperTargetIndex - 1);
                 if (wb.mBaseLayer < maxLayer &&
-                        wb.mAttachedWindow != foundW &&
-                        (foundW.mAttachedWindow == null ||
-                                wb.mAttachedWindow != foundW.mAttachedWindow) &&
-                        (wb.mAttrs.type != TYPE_APPLICATION_STARTING ||
-                                foundW.mToken == null || wb.mToken != foundW.mToken)) {
+                        wb.mAttachedWindow != wallpaperTarget &&
+                        (wallpaperTarget.mAttachedWindow == null ||
+                                wb.mAttachedWindow != wallpaperTarget.mAttachedWindow) &&
+                        (wb.mAttrs.type != TYPE_APPLICATION_STARTING
+                                || wallpaperTarget.mToken == null
+                                || wb.mToken != wallpaperTarget.mToken)) {
                     // This window is not related to the previous one in any
                     // interesting way, so stop here.
                     break;
                 }
-                foundW = wb;
-                foundI--;
+                wallpaperTarget = wb;
+                wallpaperTargetIndex--;
             }
         } else {
             if (DEBUG_WALLPAPER) Slog.v(TAG, "No wallpaper target");
         }
 
-        if (foundW == null && topCurW != null) {
-            // There is no wallpaper target, so it goes at the bottom.
-            // We will assume it is the same place as last time, if known.
-            foundW = topCurW;
-            foundI = topCurI+1;
-        } else {
-            // Okay i is the position immediately above the wallpaper.  Look at
-            // what is below it for later.
-            foundW = foundI > 0 ? windows.get(foundI - 1) : null;
-        }
+        result.setWallpaperTarget(wallpaperTarget, wallpaperTargetIndex);
+        return visible;
+    }
 
-        if (visible) {
-            if (mWallpaperTarget.mWallpaperX >= 0) {
-                mLastWallpaperX = mWallpaperTarget.mWallpaperX;
-                mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
-            }
-            if (mWallpaperTarget.mWallpaperY >= 0) {
-                mLastWallpaperY = mWallpaperTarget.mWallpaperY;
-                mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
-            }
-            if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
-            }
-            if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
-                mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
-            }
-        }
+    boolean updateWallpaperWindowsPlacement(WindowList windows,
+            WindowState wallpaperTarget, int wallpaperTargetIndex, boolean visible) {
+
+        // TODO(multidisplay): Wallpapers on main screen only.
+        final DisplayInfo displayInfo = mService.getDefaultDisplayContentLocked().getDisplayInfo();
+        final int dw = displayInfo.logicalWidth;
+        final int dh = displayInfo.logicalHeight;
 
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
@@ -722,41 +705,40 @@
                         + wallpaper + " anim layer: " + wallpaper.mWinAnimator.mAnimLayer);
 
                 // First, if this window is at the current index, then all is well.
-                if (wallpaper == foundW) {
-                    foundI--;
-                    foundW = foundI > 0 ? windows.get(foundI - 1) : null;
+                if (wallpaper == wallpaperTarget) {
+                    wallpaperTargetIndex--;
+                    wallpaperTarget = wallpaperTargetIndex > 0
+                            ? windows.get(wallpaperTargetIndex - 1) : null;
                     continue;
                 }
 
                 // The window didn't match...  the current wallpaper window,
-                // wherever it is, is in the wrong place, so make sure it is
-                // not in the list.
+                // wherever it is, is in the wrong place, so make sure it is not in the list.
                 int oldIndex = windows.indexOf(wallpaper);
                 if (oldIndex >= 0) {
-                    if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Wallpaper removing at "
-                            + oldIndex + ": " + wallpaper);
+                    if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG,
+                            "Wallpaper removing at " + oldIndex + ": " + wallpaper);
                     windows.remove(oldIndex);
                     mService.mWindowsChanged = true;
-                    if (oldIndex < foundI) {
-                        foundI--;
+                    if (oldIndex < wallpaperTargetIndex) {
+                        wallpaperTargetIndex--;
                     }
                 }
 
                 // Now stick it in. For apps over wallpaper keep the wallpaper at the bottommost
                 // layer. For keyguard over wallpaper put the wallpaper under the keyguard.
                 int insertionIndex = 0;
-                if (visible && foundW != null) {
-                    final int type = foundW.mAttrs.type;
-                    final int privateFlags = foundW.mAttrs.privateFlags;
+                if (visible && wallpaperTarget != null) {
+                    final int type = wallpaperTarget.mAttrs.type;
+                    final int privateFlags = wallpaperTarget.mAttrs.privateFlags;
                     if ((privateFlags & PRIVATE_FLAG_KEYGUARD) != 0
                             || type == TYPE_KEYGUARD_SCRIM) {
-                        insertionIndex = windows.indexOf(foundW);
+                        insertionIndex = windows.indexOf(wallpaperTarget);
                     }
                 }
-                if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
-                    Slog.v(TAG, "Moving wallpaper " + wallpaper
-                            + " from " + oldIndex + " to " + insertionIndex);
-                }
+                if (DEBUG_WALLPAPER_LIGHT || DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                        "Moving wallpaper " + wallpaper
+                        + " from " + oldIndex + " to " + insertionIndex);
 
                 windows.add(insertionIndex, wallpaper);
                 mService.mWindowsChanged = true;
@@ -764,6 +746,53 @@
             }
         }
 
+        return changed;
+    }
+
+    boolean adjustWallpaperWindows() {
+        mService.mInnerFields.mWallpaperMayChange = false;
+
+        final WindowList windows = mService.getDefaultWindowListLocked();
+        // First find top-most window that has asked to be on top of the wallpaper;
+        // all wallpapers go behind it.
+        findWallpaperTarget(windows, mFindResults);
+        final boolean targetChanged = updateWallpaperWindowsTarget(windows, mFindResults);
+        final boolean visible = updateWallpaperWindowsTargetByLayer(windows, mFindResults);
+        WindowState wallpaperTarget = mFindResults.wallpaperTarget;
+        int wallpaperTargetIndex = mFindResults.wallpaperTargetIndex;
+
+        if (wallpaperTarget == null && mFindResults.topWallpaper != null) {
+            // There is no wallpaper target, so it goes at the bottom.
+            // We will assume it is the same place as last time, if known.
+            wallpaperTarget = mFindResults.topWallpaper;
+            wallpaperTargetIndex = mFindResults.topWallpaperIndex + 1;
+        } else {
+            // Okay i is the position immediately above the wallpaper.
+            // Look at what is below it for later.
+            wallpaperTarget = wallpaperTargetIndex > 0
+                    ? windows.get(wallpaperTargetIndex - 1) : null;
+        }
+
+        if (visible) {
+            if (mWallpaperTarget.mWallpaperX >= 0) {
+                mLastWallpaperX = mWallpaperTarget.mWallpaperX;
+                mLastWallpaperXStep = mWallpaperTarget.mWallpaperXStep;
+            }
+            if (mWallpaperTarget.mWallpaperY >= 0) {
+                mLastWallpaperY = mWallpaperTarget.mWallpaperY;
+                mLastWallpaperYStep = mWallpaperTarget.mWallpaperYStep;
+            }
+            if (mWallpaperTarget.mWallpaperDisplayOffsetX != Integer.MIN_VALUE) {
+                mLastWallpaperDisplayOffsetX = mWallpaperTarget.mWallpaperDisplayOffsetX;
+            }
+            if (mWallpaperTarget.mWallpaperDisplayOffsetY != Integer.MIN_VALUE) {
+                mLastWallpaperDisplayOffsetY = mWallpaperTarget.mWallpaperDisplayOffsetY;
+            }
+        }
+
+        final boolean changed = updateWallpaperWindowsPlacement(
+                windows, wallpaperTarget, wallpaperTargetIndex, visible);
+
         if (targetChanged && DEBUG_WALLPAPER_LIGHT)  Slog.d(TAG, "New wallpaper: target="
                 + mWallpaperTarget + " lower=" + mLowerWallpaperTarget + " upper="
                 + mUpperWallpaperTarget);
@@ -859,4 +888,29 @@
             }
         }
     }
+
+    /** Helper class for storing the results of a wallpaper target find operation. */
+    final private static class FindWallpaperTargetResult {
+        int topWallpaperIndex = 0;
+        WindowState topWallpaper = null;
+        int wallpaperTargetIndex = 0;
+        WindowState wallpaperTarget = null;
+
+        void setTopWallpaper(WindowState win, int index) {
+            topWallpaper = win;
+            topWallpaperIndex = index;
+        }
+
+        void setWallpaperTarget(WindowState win, int index) {
+            wallpaperTarget = win;
+            wallpaperTargetIndex = index;
+        }
+
+        void reset() {
+            topWallpaperIndex = 0;
+            topWallpaper = null;
+            wallpaperTargetIndex = 0;
+            wallpaperTarget = null;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7e7d009..cf690a5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -114,6 +114,7 @@
 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;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.FastPrintWriter;
@@ -551,7 +552,7 @@
 
     boolean mHardKeyboardAvailable;
     boolean mShowImeWithHardKeyboard;
-    OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
+    WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
 
     private final class SettingsObserver extends ContentObserver {
@@ -597,6 +598,7 @@
     final InputManagerService mInputManager;
     final DisplayManagerInternal mDisplayManagerInternal;
     final DisplayManager mDisplayManager;
+    final Display[] mDisplays;
 
     // Who is holding the screen on.
     Session mHoldingScreenOn;
@@ -870,8 +872,8 @@
 
         mFxSession = new SurfaceSession();
         mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
-        Display[] displays = mDisplayManager.getDisplays();
-        for (Display display : displays) {
+        mDisplays = mDisplayManager.getDisplays();
+        for (Display display : mDisplays) {
             createDisplayContentLocked(display);
         }
 
@@ -2804,12 +2806,17 @@
             Rect appFrame = new Rect(0, 0, width, height);
             Rect surfaceInsets = null;
             final boolean fullscreen = win != null && win.isFullscreen(width, height);
-            // Dialog activities have windows with containing frame being very large, but not
-            // exactly fullscreen and much smaller mFrame. We use this distinction to identify
-            // dialog activities.
-            final boolean dialogWindow = win != null && !win.mContainingFrame.equals(win.mFrame);
+            final boolean freeform = win != null && win.inFreeformWorkspace();
             if (win != null) {
-                containingFrame.set(win.mContainingFrame);
+                // Containing frame will usually cover the whole screen, including dialog windows.
+                // For freeform workspace windows it will not cover the whole screen and it also
+                // won't exactly match the final freeform window frame (e.g. when overlapping with
+                // the status bar). In that case we need to use the final frame.
+                if (freeform) {
+                    containingFrame.set(win.mFrame);
+                } else {
+                    containingFrame.set(win.mContainingFrame);
+                }
                 surfaceInsets = win.getAttrs().surfaceInsets;
                 if (fullscreen) {
                     // For fullscreen windows use the window frames and insets to set the thumbnail
@@ -2828,11 +2835,9 @@
                 // screen gets the enter animation. Both appear in the mOpeningApps set.
                 enter = false;
             }
-            final boolean resizedWindow = !fullscreen && !dialogWindow;
             Animation a = mAppTransition.loadAnimation(lp, transit, enter, containingWidth,
                     containingHeight, mCurConfiguration.orientation, containingFrame, contentInsets,
-                    surfaceInsets, appFrame, isVoiceInteraction, resizedWindow,
-                    atoken.mTask.mTaskId);
+                    surfaceInsets, appFrame, isVoiceInteraction, freeform, atoken.mTask.mTaskId);
             if (a != null) {
                 if (DEBUG_ANIM) {
                     RuntimeException e = null;
@@ -5633,7 +5638,7 @@
                         int right = wf.right - cr.right;
                         int bottom = wf.bottom - cr.bottom;
                         frame.union(left, top, right, bottom);
-                        ws.getTaskBounds(stackBounds);
+                        ws.getTaskBounds(stackBounds, !BOUNDS_FOR_TOUCH);
                         if (!frame.intersect(stackBounds)) {
                             // Set frame empty if there's no intersection.
                             frame.setEmpty();
@@ -6806,12 +6811,6 @@
         mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
     }
 
-    public boolean isHardKeyboardAvailable() {
-        synchronized (mWindowMap) {
-            return mHardKeyboardAvailable;
-        }
-    }
-
     public void updateShowImeWithHardKeyboard() {
         synchronized (mWindowMap) {
             final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser(
@@ -6824,16 +6823,9 @@
         }
     }
 
-    public void setOnHardKeyboardStatusChangeListener(
-            OnHardKeyboardStatusChangeListener listener) {
-        synchronized (mWindowMap) {
-            mHardKeyboardStatusChangeListener = listener;
-        }
-    }
-
     void notifyHardKeyboardStatusChange() {
         final boolean available;
-        final OnHardKeyboardStatusChangeListener listener;
+        final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener;
         synchronized (mWindowMap) {
             listener = mHardKeyboardStatusChangeListener;
             available = mHardKeyboardAvailable;
@@ -7003,7 +6995,9 @@
     }
 
     public void displayReady() {
-        displayReady(Display.DEFAULT_DISPLAY);
+        for (Display display : mDisplays) {
+            displayReady(display.getDisplayId());
+        }
 
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
@@ -8553,312 +8547,322 @@
      * @return bitmap indicating if another pass through layout must be made.
      */
     public int handleAppTransitionReadyLocked(WindowList windows) {
-        int changes = 0;
-        int i;
         int appsCount = mOpeningApps.size();
-        boolean goodToGo = true;
+        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() + ")...");
+                        + mDisplayFrozen + " timeout="
+                        + mAppTransition.isTimeout() + ")...");
         if (!mAppTransition.isTimeout()) {
-            for (i = 0; i < appsCount && goodToGo; i++) {
+            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) {
-                    goodToGo = false;
+                if (!wtoken.allDrawn && !wtoken.startingDisplayed && !wtoken.startingMoved) {
+                    return false;
                 }
             }
 
-            if (goodToGo && mWallpaperControllerLocked.isWallpaperVisible()) {
-                goodToGo &= mWallpaperControllerLocked.wallpaperTransitionReady();
-            }
+            // If the wallpaper is visible, we need to check it's ready too.
+            return !mWallpaperControllerLocked.isWallpaperVisible() ||
+                    mWallpaperControllerLocked.wallpaperTransitionReady();
         }
-        if (goodToGo) {
-            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();
-
-            // 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;
-
-            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();
-
-            if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
-                    "New wallpaper target=" + wallpaperTarget
-                    + ", oldWallpaper=" + oldWallpaper
-                    + ", lower target=" + lowerWallpaperTarget
-                    + ", upper target=" + upperWallpaperTarget);
-
-            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;
-            }
-
-            // 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;
-                        }
-                    }
-                }
-            }
-
-            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;
-            }
-
-            // 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;
-            }
-
-            // Process all applications animating in place
-            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();
-                }
-            }
-
-            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.
-            changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT
-                    | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
-            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 changes;
+        return true;
     }
 
     private void createThumbnailAppAnimator(int transit, AppWindowToken appToken,
@@ -9764,8 +9768,8 @@
                     ": removed=" + win.mRemoved + " visible=" + win.isVisibleLw() +
                     " mHasSurface=" + win.mHasSurface +
                     " drawState=" + win.mWinAnimator.mDrawState);
-            if (win.mRemoved || !win.mHasSurface) {
-                // Window has been removed; no draw will now happen, so stop waiting.
+            if (win.mRemoved || !win.mHasSurface || !win.mPolicyVisibility) {
+                // Window has been removed or hidden; no draw will now happen, so stop waiting.
                 if (DEBUG_SCREEN_ON) Slog.w(TAG, "Aborted waiting for drawn: " + win);
                 mWaitingForDrawn.remove(win);
             } else if (win.hasDrawnLw()) {
@@ -10417,23 +10421,6 @@
         }
     }
 
-    // It is assumed that this method is called only by InputMethodManagerService.
-    public void saveLastInputMethodWindowForTransition() {
-        synchronized (mWindowMap) {
-            // TODO(multidisplay): Pass in the displayID.
-            DisplayContent displayContent = getDefaultDisplayContentLocked();
-            if (mInputMethodWindow != null) {
-                mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
-            }
-        }
-    }
-
-    public int getInputMethodWindowVisibleHeight() {
-        synchronized (mWindowMap) {
-            return mPolicy.getInputMethodWindowVisibleHeightLw();
-        }
-    }
-
     @Override
     public boolean hasNavigationBar() {
         return mPolicy.hasNavigationBar();
@@ -11023,10 +11010,6 @@
         synchronized (mWindowMap) { }
     }
 
-    public interface OnHardKeyboardStatusChangeListener {
-        public void onHardKeyboardStatusChange(boolean available);
-    }
-
     void debugLayoutRepeats(final String msg, int pendingLayoutChanges) {
         if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) {
             Slog.v(TAG, "Layouts looping: " + msg + ", mPendingLayoutChanges = 0x" +
@@ -11285,12 +11268,18 @@
                 final WindowList windows = getDefaultWindowListLocked();
                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                     final WindowState win = windows.get(winNdx);
+                    final boolean isForceHiding = mPolicy.isForceHiding(win.mAttrs);
                     if (win.isVisibleLw()
-                            && (win.mAppToken != null || mPolicy.isForceHiding(win.mAttrs))) {
+                            && (win.mAppToken != null || isForceHiding)) {
                         win.mWinAnimator.mDrawState = WindowStateAnimator.DRAW_PENDING;
                         // Force add to mResizingWindows.
                         win.mLastContentInsets.set(-1, -1, -1, -1);
                         mWaitingForDrawn.add(win);
+
+                        // No need to wait for the windows below Keyguard.
+                        if (isForceHiding) {
+                            break;
+                        }
                     }
                 }
                 requestTraversalLocked();
@@ -11328,5 +11317,39 @@
                 mAppTransition.registerListenerLocked(listener);
             }
         }
+
+        @Override
+        public int getInputMethodWindowVisibleHeight() {
+            synchronized (mWindowMap) {
+                return mPolicy.getInputMethodWindowVisibleHeightLw();
+            }
+        }
+
+        @Override
+        public void saveLastInputMethodWindowForTransition() {
+            synchronized (mWindowMap) {
+                // TODO(multidisplay): Pass in the displayID.
+                DisplayContent displayContent = getDefaultDisplayContentLocked();
+                if (mInputMethodWindow != null) {
+                    mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
+                }
+            }
+        }
+
+        @Override
+        public boolean isHardKeyboardAvailable() {
+            synchronized (mWindowMap) {
+                return mHardKeyboardAvailable;
+            }
+        }
+
+        @Override
+        public void setOnHardKeyboardStatusChangeListener(
+                OnHardKeyboardStatusChangeListener listener) {
+            synchronized (mWindowMap) {
+                mHardKeyboardStatusChangeListener = listener;
+            }
+        }
+
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b56b1f9..761e5eb 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -80,8 +80,14 @@
     static final String TAG = "WindowState";
 
     // The minimal size of a window within the usable area of the freeform stack.
-    static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
-    static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+    private static final int MINIMUM_VISIBLE_WIDTH_IN_DP = 48;
+    private static final int MINIMUM_VISIBLE_HEIGHT_IN_DP = 32;
+
+    // The thickness of a window resize handle outside the window bounds on the free form workspace
+    // to capture touch events in that area.
+    private static final int RESIZE_HANDLE_WIDTH_IN_DP = 10;
+
+    static final boolean BOUNDS_FOR_TOUCH = true;
 
     final WindowManagerService mService;
     final WindowManagerPolicy mPolicy;
@@ -541,9 +547,8 @@
         mHaveFrame = true;
 
         final Task task = mAppToken != null ? getTask() : null;
-        final boolean isFreeFormWorkspace = task != null && task.mStack != null &&
-                task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
         final boolean nonFullscreenTask = task != null && !task.isFullscreen();
+        final boolean freeformWorkspace = inFreeformWorkspace();
         if (nonFullscreenTask) {
             task.getBounds(mContainingFrame);
             final WindowState imeWin = mService.mInputMethodWindow;
@@ -553,7 +558,7 @@
                 mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
             }
 
-            if (isFreeFormWorkspace) {
+            if (freeformWorkspace) {
                 // In free form mode we have only to set the rectangle if it wasn't set already. No
                 // need to intersect it with the (visible) "content frame" since it is allowed to
                 // be outside the visible desktop.
@@ -669,7 +674,7 @@
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
-        if (isFreeFormWorkspace && !mFrame.isEmpty()) {
+        if (freeformWorkspace && !mFrame.isEmpty()) {
             // Keep the frame out of the blocked system area, limit it in size to the content area
             // and make sure that there is always a minimum visible so that the user can drag it
             // into a usable area..
@@ -910,10 +915,22 @@
         return mDisplayContent.getHomeStack();
     }
 
-    void getTaskBounds(Rect bounds) {
+    /**
+     * Retrieves the bounds for a task.
+     * @param bounds The rect which gets the bounds.
+     * @param forTouch Pass in BOUNDS_FOR_TOUCH to get touch related bounds, otherwise visible
+     *        bounds will be returned.
+     */
+    void getTaskBounds(Rect bounds, boolean forTouch) {
         final Task task = getTask();
         if (task != null) {
             task.getBounds(bounds);
+            if (forTouch == BOUNDS_FOR_TOUCH) {
+                if (inFreeformWorkspace()) {
+                    final int delta = calculatePixelFromDp(RESIZE_HANDLE_WIDTH_IN_DP);
+                    bounds.inset(-delta, -delta);
+                }
+            }
             return;
         }
         bounds.set(mFrame);
@@ -1612,6 +1629,12 @@
         }
     }
 
+    boolean inFreeformWorkspace() {
+        final Task task = getTask();
+        return task != null && task.mStack != null &&
+                task.mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+    }
+
     private int calculatePixelFromDp(int dp) {
         final Configuration serviceConfig = mService.mCurConfiguration;
         // TODO(multidisplay): Update Dp to that of display stack is on.
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 7aa48ab..109e627 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1590,8 +1590,6 @@
         final int left = ((int) shownFrame.left) - attrs.surfaceInsets.left;
         final int top = ((int) shownFrame.top) - attrs.surfaceInsets.top;
         if (mSurfaceX != left || mSurfaceY != top) {
-            mSurfaceX = left;
-            mSurfaceY = top;
             if (mAnimating) {
                 // If this window (or its app token) is animating, then the position
                 // of the surface will be re-computed on the next animation frame.
@@ -1599,6 +1597,8 @@
                 // transformation is being applied by the animation.
                 return;
             }
+            mSurfaceX = left;
+            mSurfaceY = top;
             if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset");
             SurfaceControl.openTransaction();
             try {
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/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 7fc56ec..b57e3ea 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
 import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
 import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.TEXT;
@@ -277,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();
 
@@ -1042,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);
@@ -1117,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) {
@@ -1136,7 +1136,7 @@
 
     void loadDeviceOwner() {
         synchronized (this) {
-            mDeviceOwner = DeviceOwner.load();
+            mOwners.load();
             updateDeviceOwnerLocked();
         }
     }
@@ -1804,8 +1804,7 @@
         Set<Integer> usersWithProfileOwners;
         Set<Integer> usersWithData;
         synchronized(this) {
-            usersWithProfileOwners = mDeviceOwner != null
-                    ? mDeviceOwner.getProfileOwnerKeys() : new HashSet<Integer>();
+            usersWithProfileOwners = mOwners.getProfileOwnerKeys();
             usersWithData = new HashSet<Integer>();
             for (int i = 0; i < mUserData.size(); i++) {
                 usersWithData.add(mUserData.keyAt(i));
@@ -2957,7 +2956,8 @@
             }
             boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
             if (requireEntry) {
-                utils.requireCredentialEntry(UserHandle.USER_ALL);
+                utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+                        UserHandle.USER_ALL);
             }
             synchronized (this) {
                 int newOwner = requireEntry ? callingUid : -1;
@@ -3089,7 +3089,8 @@
             mPowerManager.goToSleep(SystemClock.uptimeMillis(),
                     PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
             // Ensure the device is locked
-            new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+            new LockPatternUtils(mContext).requireStrongAuth(
+                    STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
             getWindowManager().lockNow(null);
         } catch (RemoteException e) {
         } finally {
@@ -4114,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");
         }
@@ -4133,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);
 
@@ -4160,9 +4155,8 @@
             return false;
         }
         synchronized (this) {
-            return mDeviceOwner != null
-                    && mDeviceOwner.hasDeviceOwner()
-                    && mDeviceOwner.getDeviceOwnerPackageName().equals(packageName);
+            return mOwners.hasDeviceOwner()
+                    && mOwners.getDeviceOwnerPackageName().equals(packageName);
         }
     }
 
@@ -4172,11 +4166,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceOwner()) {
-                return mDeviceOwner.getDeviceOwnerPackageName();
-            }
+            return mOwners.getDeviceOwnerPackageName();
         }
-        return null;
     }
 
     @Override
@@ -4186,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);
         }
     }
@@ -4228,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);
             }
         }
     }
@@ -4241,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");
@@ -4260,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;
         }
     }
@@ -4298,9 +4293,8 @@
             return false;
         }
         synchronized (this) {
-            return mDeviceOwner != null
-                    && mDeviceOwner.hasDeviceInitializer()
-                    && mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
+            return mOwners.hasDeviceInitializer()
+                    && mOwners.getDeviceInitializerPackageName().equals(packageName);
         }
     }
 
@@ -4310,8 +4304,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
-                return mDeviceOwner.getDeviceInitializerPackageName();
+            if (mOwners.hasDeviceInitializer()) {
+                return mOwners.getDeviceInitializerPackageName();
             }
         }
         return null;
@@ -4323,8 +4317,8 @@
             return null;
         }
         synchronized (this) {
-            if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
-                return mDeviceOwner.getDeviceInitializerComponent();
+            if (mOwners.hasDeviceInitializer()) {
+                return mOwners.getDeviceInitializerComponent();
             }
         }
         return null;
@@ -4352,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);
             }
@@ -4368,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;
         }
     }
@@ -4397,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);
         }
     }
 
@@ -4557,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;
         }
@@ -4669,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.");
         }
@@ -4770,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));
@@ -4994,12 +4972,18 @@
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
             try {
-                // Removing those that go from the managed profile to the primary user.
+                UserInfo parent = mUserManager.getProfileParent(callingUserId);
+                if (parent == null) {
+                    Slog.e(LOG_TAG, "Cannot call clearCrossProfileIntentFilter if there is no "
+                            + "parent");
+                    return;
+                }
+                // Removing those that go from the managed profile to the parent.
                 pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName());
-                // And those that go from the primary user to the managed profile.
+                // And those that go from the parent to the managed profile.
                 // If we want to support multiple managed profiles, we will have to only remove
                 // those that have callingUserId as their target.
-                pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER, who.getPackageName());
+                pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
@@ -6253,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();
                 }
@@ -6326,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),
@@ -6340,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..c37b4f9
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -0,0 +1,589 @@
+/*
+ * 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.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.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+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 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 HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
+
+    // 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)) {
+                // Legacy file exists, write to new files and remove the legacy one.
+                writeDeviceOwner();
+                for (int userId : getProfileOwnerKeys()) {
+                    writeProfileOwner(userId);
+                }
+                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;
+    }
+
+    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) {
+            new DeviceOwnerReadWriter().writeToFileLocked();
+        }
+    }
+
+    void writeProfileOwner(int userId) {
+        synchronized (this) {
+            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()) {
+                // No contents, remove the file.
+                if (mFile.exists()) {
+                    if (!mFile.delete()) {
+                        Slog.e(TAG, "Failed to remove " + mFile.getPath());
+                    }
+                }
+                return;
+            }
+
+            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()) {
+                return;
+            }
+            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;
+                        }
+                    }
+                    // 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 ed32c76..21dd647b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -546,7 +546,7 @@
         if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             try {
                 Slog.i(TAG, "Input Method Service");
-                imm = new InputMethodManagerService(context, wm);
+                imm = new InputMethodManagerService(context);
                 ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm);
             } catch (Throwable e) {
                 reportWtf("starting Input Manager Service", e);
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/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
new file mode 100644
index 0000000..03e8d69
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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.Context;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+
+/**
+ * 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 OwnersTest extends AndroidTestCase {
+
+    private static class OwnersSub extends Owners {
+        private final File mLegacyFile;
+        private final File mDeviceOwnerFile;
+        private final File mProfileOwnerBase;
+
+        public OwnersSub(Context context, File legacyFile, File deviceOwnerFile,
+                File profileOwnerBase) {
+            super(context);
+            mLegacyFile = legacyFile;
+            mDeviceOwnerFile = deviceOwnerFile;
+            mProfileOwnerBase = profileOwnerBase;
+        }
+
+        @Override
+        File getLegacyConfigFileWithTestOverride() {
+            return mLegacyFile;
+        }
+
+        @Override
+        File getDeviceOwnerFileWithTestOverride() {
+            return mDeviceOwnerFile;
+        }
+
+        @Override
+        File getProfileOwnerFileWithTestOverride(int userId) {
+            return new File(mDeviceOwnerFile.getAbsoluteFile() + "-" + userId);
+        }
+    }
+
+    // TODO Write tests
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 2d47c24..86f5ed7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -38,7 +38,8 @@
 
     @Override
     public void setUp() throws Exception {
-        mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        super.setUp();
+        mUserManager = UserManager.get(getContext());
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
         getContext().registerReceiver(new BroadcastReceiver() {
             @Override
@@ -64,14 +65,18 @@
     private void removeExistingUsers() {
         List<UserInfo> list = mUserManager.getUsers();
         for (UserInfo user : list) {
-            if (user.id != UserHandle.USER_OWNER) {
+            // Keep system and primary user.
+            // We do not have to keep primary user, but in split system user mode, we need it
+            // until http://b/22976637 is fixed.  Right now in split system user mode, you need to
+            // switch to primary user and run tests under primary user.
+            if (user.id != UserHandle.USER_SYSTEM && !user.isPrimary()) {
                 removeUser(user.id);
             }
         }
     }
 
-    public void testHasPrimary() throws Exception {
-        assertTrue(findUser(0));
+    public void testHasSystemUser() throws Exception {
+        assertTrue(findUser(UserHandle.USER_SYSTEM));
     }
 
     public void testAddUser() throws Exception {
@@ -122,10 +127,11 @@
 
     // Make sure only one managed profile can be created
     public void testAddManagedProfile() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo userInfo1 = createProfileForUser("Managed 1",
-                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
         UserInfo userInfo2 = createProfileForUser("Managed 2",
-                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
         assertNotNull(userInfo1);
         assertNull(userInfo2);
         // Verify that current user is not a managed profile
@@ -133,17 +139,18 @@
     }
 
     public void testGetUserCreationTime() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
         UserInfo profile = createProfileForUser("Managed 1",
-                UserInfo.FLAG_MANAGED_PROFILE, UserHandle.USER_OWNER);
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
         assertNotNull(profile);
         assertTrue("creationTime must be set when the profile is created",
                 profile.creationTime > 0);
         assertEquals(profile.creationTime, mUserManager.getUserCreationTime(
                 new UserHandle(profile.id)));
 
-        long ownerCreationTime = mUserManager.getUserInfo(UserHandle.USER_OWNER).creationTime;
+        long ownerCreationTime = mUserManager.getUserInfo(primaryUserId).creationTime;
         assertEquals(ownerCreationTime, mUserManager.getUserCreationTime(
-                new UserHandle(UserHandle.USER_OWNER)));
+                new UserHandle(primaryUserId)));
 
         try {
             int noSuchUserId = 100500;
@@ -177,11 +184,11 @@
     }
 
     public void testSerialNumber() {
-        UserInfo user1 = createUser("User 1", UserInfo.FLAG_RESTRICTED);
+        UserInfo user1 = createUser("User 1", 0);
         int serialNumber1 = user1.serialNumber;
         assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
         assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
-        UserInfo user2 = createUser("User 2", UserInfo.FLAG_RESTRICTED);
+        UserInfo user2 = createUser("User 2", 0);
         int serialNumber2 = user2.serialNumber;
         assertFalse(serialNumber1 == serialNumber2);
         assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
@@ -203,17 +210,15 @@
     }
 
     public void testRestrictions() {
-        List<UserInfo> users = mUserManager.getUsers();
-        if (users.size() > 1) {
-            Bundle restrictions = new Bundle();
-            restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
-            restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
-            mUserManager.setUserRestrictions(restrictions, new UserHandle(users.get(1).id));
-            Bundle stored = mUserManager.getUserRestrictions(new UserHandle(users.get(1).id));
-            assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
-            assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
-            assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
-        }
+        UserInfo testUser = createUser("User 1", 0);
+        Bundle restrictions = new Bundle();
+        restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
+        restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
+        mUserManager.setUserRestrictions(restrictions, new UserHandle(testUser.id));
+        Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
+        assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
+        assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
+        assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);
     }
 
     private void removeUser(int userId) {
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index fb9a3a3..b021e80 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -61,6 +61,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Scanner;
+import java.util.Set;
 
 /**
  * UsbDeviceManager manages USB state in device mode.
@@ -148,6 +149,7 @@
     private String[] mAccessoryStrings;
     private UsbDebuggingManager mDebuggingManager;
     private final UsbAlsaManager mUsbAlsaManager;
+    private Intent mBroadcastedIntent;
 
     private class AdbSettingsObserver extends ContentObserver {
         public AdbSettingsObserver() {
@@ -427,7 +429,7 @@
             if (DEBUG) Slog.d(TAG, "setUsbDataUnlocked: " + enable);
             mUsbDataUnlocked = enable;
             updateUsbNotification();
-            updateUsbStateBroadcast();
+            updateUsbStateBroadcastIfNeeded();
             setEnabledFunctions(mCurrentFunctions, true);
         }
 
@@ -574,7 +576,33 @@
             }
         }
 
-        private void updateUsbStateBroadcast() {
+        private boolean isUsbStateChanged(Intent intent) {
+            final Set<String> keySet = intent.getExtras().keySet();
+            if (mBroadcastedIntent == null) {
+                for (String key : keySet) {
+                    if (intent.getBooleanExtra(key, false)) {
+                        // MTP function is enabled by default.
+                        if (UsbManager.USB_FUNCTION_MTP.equals(key)) {
+                            continue;
+                        }
+                        return true;
+                    }
+                }
+            } else {
+                if (!keySet.equals(mBroadcastedIntent.getExtras().keySet())) {
+                    return true;
+                }
+                for (String key : keySet) {
+                    if (intent.getBooleanExtra(key, false) !=
+                        mBroadcastedIntent.getBooleanExtra(key, false)) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+
+        private void updateUsbStateBroadcastIfNeeded() {
             // send a sticky broadcast containing current USB state
             Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
@@ -586,13 +614,25 @@
             if (mCurrentFunctions != null) {
                 String[] functions = mCurrentFunctions.split(",");
                 for (int i = 0; i < functions.length; i++) {
-                    intent.putExtra(functions[i], true);
+                    final String function = functions[i];
+                    if (UsbManager.USB_FUNCTION_NONE.equals(function)) {
+                        continue;
+                    }
+                    intent.putExtra(function, true);
                 }
             }
 
-            if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " connected: " + mConnected
-                                    + " configured: " + mConfigured);
+            // send broadcast intent only if the USB state has changed
+            if (!isUsbStateChanged(intent)) {
+                if (DEBUG) {
+                    Slog.d(TAG, "skip broadcasting " + intent + " extras: " + intent.getExtras());
+                }
+                return;
+            }
+
+            if (DEBUG) Slog.d(TAG, "broadcasting " + intent + " extras: " + intent.getExtras());
             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+            mBroadcastedIntent = intent;
         }
 
         private void updateUsbFunctions() {
@@ -670,7 +710,7 @@
                         setEnabledFunctions(null, false);
                     }
                     if (mBootCompleted) {
-                        updateUsbStateBroadcast();
+                        updateUsbStateBroadcastIfNeeded();
                         updateUsbFunctions();
                     }
                     break;
@@ -694,7 +734,7 @@
                 case MSG_SYSTEM_READY:
                     updateUsbNotification();
                     updateAdbNotification();
-                    updateUsbStateBroadcast();
+                    updateUsbStateBroadcastIfNeeded();
                     updateUsbFunctions();
                     break;
                 case MSG_BOOT_COMPLETED:
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 263c5e9..bfb7a50 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -266,6 +266,13 @@
     public static final String KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL =
             "carrier_instant_lettering_available_bool";
 
+    /*
+     * Flag specifying whether IMS should be the first phone attempted for E911 even if the
+     * phone is not in service.
+     */
+    public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL
+            = "carrier_use_ims_first_for_emergency_bool";
+
     /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
@@ -358,6 +365,19 @@
     public static final String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
 
     /**
+     * Determines whether conference calls are supported by a carrier.  When {@code true},
+     * conference calling is supported, {@code false otherwise}.
+     * @hide
+     */
+    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
@@ -418,6 +438,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_INSTANT_LETTERING_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true);
         sDefaults.putBoolean(KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL, false);
         sDefaults.putBoolean(KEY_DTMF_TYPE_ENABLED_BOOL, false);
         sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true);
@@ -457,6 +478,8 @@
         sDefaults.putBoolean(KEY_FORCE_HOME_NETWORK_BOOL, false);
         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);
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 79146f3..273cc93 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1135,6 +1135,8 @@
         "VI", // U.S. Virgin Islands
     };
 
+    private static final String KOREA_ISO_COUNTRY_CODE = "KR";
+
     /**
      * Breaks the given number down and formats it according to the rules
      * for the country the number is from.
@@ -1455,7 +1457,14 @@
         String result = null;
         try {
             PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
-            result = util.formatInOriginalFormat(pn, defaultCountryIso);
+            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.
+                result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+            } else {
+                result = util.formatInOriginalFormat(pn, defaultCountryIso);
+            }
         } catch (NumberParseException e) {
         }
         return result;
diff --git a/tests/TileBenchmark/Android.mk b/tests/TileBenchmark/Android.mk
deleted file mode 100644
index 9a057af..0000000
--- a/tests/TileBenchmark/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES :=
-
-LOCAL_PACKAGE_NAME := TileBenchmark
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-include $(BUILD_PACKAGE)
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/.gitignore b/tests/UiBench/.gitignore
new file mode 100644
index 0000000..c39eac2
--- /dev/null
+++ b/tests/UiBench/.gitignore
@@ -0,0 +1,5 @@
+.gradle
+.idea
+*.iml
+build
+local.properties
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
new file mode 100644
index 0000000..1e5b117
--- /dev/null
+++ b/tests/UiBench/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# omit gradle 'build' dir
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+# use appcompat/support lib from the tree, so improvements/
+# regressions are reflected in test data
+LOCAL_RESOURCE_DIR := \
+    $(LOCAL_PATH)/res \
+    frameworks/support/v7/appcompat/res
+
+LOCAL_AAPT_FLAGS := \
+    --extra-packages android.support.v7.appcompat
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-v4 \
+    android-support-v7-appcompat
+
+LOCAL_PACKAGE_NAME := UiBench
+
+include $(BUILD_PACKAGE)
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
new file mode 100644
index 0000000..6677e0d
--- /dev/null
+++ b/tests/UiBench/AndroidManifest.xml
@@ -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
+  -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.test.uibench">
+
+    <application
+        android:allowBackup="false"
+        android:theme="@style/Theme.AppCompat.Light.DarkActionBar">
+        <uses-library android:name="android.test.runner" />
+
+        <!-- Root navigation activity -->
+        <activity
+            android:name=".MainActivity"
+            android:label="UiBench">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <!-- Tests -->
+        <activity
+            android:name=".GlTextureViewActivity"
+            android:label="Microbenchmarks/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="Microbenchmarks/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=".TrivialAnimationActivity"
+            android:label="Microbenchmarks/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 ListView" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/tests/UiBench/build.gradle b/tests/UiBench/build.gradle
new file mode 100644
index 0000000..bf0ed11
--- /dev/null
+++ b/tests/UiBench/build.gradle
@@ -0,0 +1,37 @@
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        classpath 'com.android.tools.build:gradle:1.3.0'
+
+    }
+}
+
+apply plugin: 'com.android.application'
+
+android {
+    compileSdkVersion 23
+    buildToolsVersion "22.0.0"
+
+    defaultConfig {
+        minSdkVersion 14
+        targetSdkVersion 23
+        versionCode 1
+        versionName "1.0"
+    }
+
+    sourceSets {
+        main {
+            manifest.srcFile 'AndroidManifest.xml'
+            java.srcDirs = ['src']
+            res.srcDirs = ['res']
+        }
+    }
+}
+
+dependencies {
+    // 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'
+}
diff --git a/tests/UiBench/gradle/wrapper/gradle-wrapper.jar b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..8c0fb64
--- /dev/null
+++ b/tests/UiBench/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/tests/UiBench/gradle/wrapper/gradle-wrapper.properties b/tests/UiBench/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..12582f8
--- /dev/null
+++ b/tests/UiBench/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Aug 26 10:51:13 PDT 2015
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
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/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..ce79259
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/GlTextureViewActivity.java
@@ -0,0 +1,413 @@
+/*
+ * 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.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.SurfaceTexture;
+import android.opengl.GLUtils;
+import android.os.Bundle;
+import android.os.Environment;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.TextureView;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+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 java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+
+import static android.opengl.GLES20.*;
+
+public class GlTextureViewActivity extends AppCompatActivity implements TextureView.SurfaceTextureListener {
+    private RenderThread 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 RenderThread(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(RenderThread.LOG_TAG, "Could not wait for render thread");
+        }
+        return true;
+    }
+
+    @Override
+    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+    }
+
+    private static class RenderThread extends Thread {
+        private 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;
+
+        RenderThread(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
+            };
+        }
+
+        void finish() {
+            mFinished = true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/tests/UiBench/src/com/android/test/uibench/MainActivity.java b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
new file mode 100644
index 0000000..2111274
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/MainActivity.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.test.uibench;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+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.ListView;
+import android.widget.SimpleAdapter;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity {
+    private static final String EXTRA_PATH = "activity_path";
+    private static final String CATEGORY_HWUI_TEST = "com.android.test.uibench.TEST";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        Intent intent = getIntent();
+        String path = intent.getStringExtra(EXTRA_PATH);
+
+        if (path == null) {
+            path = "";
+        } else {
+            // not root level, display where we are in the hierarchy
+            setTitle(path);
+        }
+
+        FragmentManager fm = getSupportFragmentManager();
+        if (fm.findFragmentById(android.R.id.content) == null) {
+            ListFragment listFragment = new ListFragment() {
+                @Override
+                @SuppressWarnings("unchecked")
+                public void onListItemClick(ListView l, View v, int position, long id) {
+                    Map<String, Object> map = (Map<String, Object>)l.getItemAtPosition(position);
+
+                    Intent intent = (Intent) map.get("intent");
+                    startActivity(intent);
+                }
+
+                @Override
+                public void onViewCreated(View view, Bundle savedInstanceState) {
+                    super.onViewCreated(view, savedInstanceState);
+                    getListView().setTextFilterEnabled(true);
+                }
+            };
+            listFragment.setListAdapter(new SimpleAdapter(this, getData(path),
+                    android.R.layout.simple_list_item_1, new String[] { "title" },
+                    new int[] { android.R.id.text1 }));
+            fm.beginTransaction().add(android.R.id.content, listFragment).commit();
+        }
+    }
+
+    protected List<Map<String, Object>> getData(String prefix) {
+        List<Map<String, Object>> myData = new ArrayList<>();
+
+        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
+        mainIntent.addCategory(CATEGORY_HWUI_TEST);
+
+        PackageManager pm = getPackageManager();
+        List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
+
+        if (null == list)
+            return myData;
+
+        String[] prefixPath;
+        String prefixWithSlash = prefix;
+
+        if (prefix.equals("")) {
+            prefixPath = null;
+        } else {
+            prefixPath = prefix.split("/");
+            prefixWithSlash = prefix + "/";
+        }
+
+        int len = list.size();
+
+        Map<String, Boolean> entries = new HashMap<>();
+
+        for (int i = 0; i < len; i++) {
+            ResolveInfo info = list.get(i);
+            CharSequence labelSeq = info.loadLabel(pm);
+            String label = labelSeq != null
+                    ? labelSeq.toString()
+                    : info.activityInfo.name;
+
+            if (prefixWithSlash.length() == 0 || label.startsWith(prefixWithSlash)) {
+
+                String[] labelPath = label.split("/");
+
+                String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
+
+                if ((prefixPath != null ? prefixPath.length : 0) == labelPath.length - 1) {
+                    addItem(myData, nextLabel, activityIntent(
+                            info.activityInfo.applicationInfo.packageName,
+                            info.activityInfo.name));
+                } else {
+                    if (entries.get(nextLabel) == null) {
+                        addItem(myData, nextLabel, browseIntent(prefix.equals("") ?
+                                nextLabel : prefix + "/" + nextLabel));
+                        entries.put(nextLabel, true);
+                    }
+                }
+            }
+        }
+
+        Collections.sort(myData, sDisplayNameComparator);
+
+        return myData;
+    }
+
+    private final static Comparator<Map<String, Object>> sDisplayNameComparator =
+            new Comparator<Map<String, Object>>() {
+                private final Collator collator = Collator.getInstance();
+
+                public int compare(Map<String, Object> map1, Map<String, Object> map2) {
+                    return collator.compare(map1.get("title"), map2.get("title"));
+                }
+            };
+
+    protected Intent activityIntent(String pkg, String componentName) {
+        Intent result = new Intent();
+        result.setClassName(pkg, componentName);
+        return result;
+    }
+
+    protected Intent browseIntent(String path) {
+        Intent result = new Intent();
+        result.setClass(this, MainActivity.class);
+        result.putExtra(EXTRA_PATH, path);
+        return result;
+    }
+
+    protected void addItem(List<Map<String, Object>> data, String name, Intent intent) {
+        Map<String, Object> temp = new HashMap<>();
+        temp.put("title", name);
+        temp.put("intent", intent);
+        data.add(temp);
+    }
+}
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
new file mode 100644
index 0000000..0af3471
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialListActivity.java
@@ -0,0 +1,55 @@
+/*
+ * 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.ArrayAdapter;
+
+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;
+    }
+
+    @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();
+        }
+    }
+}
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/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/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index b76ec17..567002e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -33,6 +33,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
@@ -227,16 +228,18 @@
      * Find the background color for this bar from the theme attributes. Only relevant to StatusBar
      * and NavigationBar.
      * <p/>
-     * Returns 0 if not found.
+     * Returns null if not found.
      *
      * @param colorAttrName the attribute name for the background color
      * @param translucentAttrName the attribute name for the translucency property of the bar.
      *
      * @throws NumberFormatException if color resolved to an invalid string.
      */
-    protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
+    @Nullable
+    protected Integer getBarColor(@NonNull String colorAttrName,
+            @NonNull String translucentAttrName) {
         if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
-            return 0;
+            return null;
         }
         RenderResources renderResources = getContext().getRenderResources();
         // First check if the bar is translucent.
@@ -251,10 +254,11 @@
         if (transparent) {
             return getColor(renderResources, colorAttrName);
         }
-        return 0;
+        return null;
     }
 
-    private static int getColor(RenderResources renderResources, String attr) {
+    @Nullable
+    private static Integer getColor(RenderResources renderResources, String attr) {
         // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
         ResourceValue resource = renderResources.findItemInTheme(attr, true);
         // Form @color/bar to the #AARRGGBB
@@ -275,7 +279,7 @@
                 }
             }
         }
-        return 0;
+        return null;
     }
 
     private ResourceValue getResourceValue(String reference) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9c89bfe..d50ce23 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -65,8 +65,8 @@
         super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
                 "navigation_bar.xml", simulatedPlatformVersion);
 
-        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
-        setBackgroundColor(color == 0 ? 0xFF000000 : color);
+        Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+        setBackgroundColor(color == null ? 0xFF000000 : color);
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 2dc7c65..95a5a58 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -71,8 +71,9 @@
         // FIXME: use FILL_H?
         setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
 
-        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
-        setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
+        Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+        setBackgroundColor(
+                color == null ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
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/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index ac7c409..24e1ce7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -421,8 +421,7 @@
                     gc.setComposite(AlphaComposite.Src);
 
                     gc.setColor(new Color(0x00000000, true));
-                    gc.fillRect(0, 0,
-                            mMeasuredScreenWidth, mMeasuredScreenHeight);
+                    gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
 
                     // done
                     gc.dispose();
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);