Merge "Added config system navigation keys." into nyc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index cb42b86..2f376b3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36315,6 +36315,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
     field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
@@ -44705,6 +44706,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44799,6 +44801,7 @@
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
     field public java.lang.CharSequence actionLabel;
+    field public java.lang.String[] contentMimeTypes;
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
@@ -44870,6 +44873,7 @@
     method public abstract java.lang.CharSequence getSelectedText(int);
     method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
     method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public abstract boolean performContextMenuAction(int);
     method public abstract boolean performEditorAction(int);
     method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44903,6 +44907,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44915,6 +44920,17 @@
     method public void setTarget(android.view.inputmethod.InputConnection);
   }
 
+  public class InputContentInfo implements android.os.Parcelable {
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public int describeContents();
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
+  }
+
   public abstract interface InputMethod {
     method public abstract void attachToken(android.os.IBinder);
     method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/api/system-current.txt b/api/system-current.txt
index 98b66c0..59be574 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -31652,6 +31652,7 @@
     method public static void installPackage(android.content.Context, java.io.File, boolean) throws java.io.IOException;
     method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener, android.os.Handler) throws java.io.IOException;
     method public static void processPackage(android.content.Context, java.io.File, android.os.RecoverySystem.ProgressListener) throws java.io.IOException;
+    method public static void rebootWipeAb(android.content.Context, java.io.File, java.lang.String) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
     method public static void rebootWipeUserData(android.content.Context) throws java.io.IOException;
     method public static void scheduleUpdateOnBoot(android.content.Context, java.io.File) throws java.io.IOException;
@@ -39163,6 +39164,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
     field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
@@ -47707,6 +47709,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -47801,6 +47804,7 @@
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
     field public java.lang.CharSequence actionLabel;
+    field public java.lang.String[] contentMimeTypes;
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
@@ -47872,6 +47876,7 @@
     method public abstract java.lang.CharSequence getSelectedText(int);
     method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
     method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public abstract boolean performContextMenuAction(int);
     method public abstract boolean performEditorAction(int);
     method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -47905,6 +47910,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -47917,6 +47923,17 @@
     method public void setTarget(android.view.inputmethod.InputConnection);
   }
 
+  public class InputContentInfo implements android.os.Parcelable {
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public int describeContents();
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
+  }
+
   public abstract interface InputMethod {
     method public abstract void attachToken(android.os.IBinder);
     method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/api/test-current.txt b/api/test-current.txt
index d20f87a..08a9243 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36393,6 +36393,7 @@
     field public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 2048; // 0x800
     field public static final int CAPABILITY_SUPPORT_HOLD = 2; // 0x2
     field public static final int CAPABILITY_SWAP_CONFERENCE = 8; // 0x8
+    field public static final java.lang.String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
     field public static final java.lang.String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
     field public static final java.lang.String EXTRA_CALL_SUBJECT = "android.telecom.extra.CALL_SUBJECT";
     field public static final java.lang.String EXTRA_CHILD_ADDRESS = "android.telecom.extra.CHILD_ADDRESS";
@@ -44785,6 +44786,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44879,6 +44881,7 @@
     field public static final int IME_NULL = 0; // 0x0
     field public int actionId;
     field public java.lang.CharSequence actionLabel;
+    field public java.lang.String[] contentMimeTypes;
     field public android.os.Bundle extras;
     field public int fieldId;
     field public java.lang.String fieldName;
@@ -44950,6 +44953,7 @@
     method public abstract java.lang.CharSequence getSelectedText(int);
     method public abstract java.lang.CharSequence getTextAfterCursor(int, int);
     method public abstract java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public abstract boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public abstract boolean performContextMenuAction(int);
     method public abstract boolean performEditorAction(int);
     method public abstract boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44983,6 +44987,7 @@
     method public java.lang.CharSequence getSelectedText(int);
     method public java.lang.CharSequence getTextAfterCursor(int, int);
     method public java.lang.CharSequence getTextBeforeCursor(int, int);
+    method public boolean insertContent(android.view.inputmethod.InputContentInfo, android.os.Bundle);
     method public boolean performContextMenuAction(int);
     method public boolean performEditorAction(int);
     method public boolean performPrivateCommand(java.lang.String, android.os.Bundle);
@@ -44995,6 +45000,17 @@
     method public void setTarget(android.view.inputmethod.InputConnection);
   }
 
+  public class InputContentInfo implements android.os.Parcelable {
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription);
+    ctor public InputContentInfo(android.net.Uri, android.content.ClipDescription, android.net.Uri);
+    method public int describeContents();
+    method public android.net.Uri getContentUri();
+    method public android.content.ClipDescription getDescription();
+    method public android.net.Uri getLinkUri();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputContentInfo> CREATOR;
+  }
+
   public abstract interface InputMethod {
     method public abstract void attachToken(android.os.IBinder);
     method public abstract void bindInput(android.view.inputmethod.InputBinding);
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 224823e..ba16e67 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -1095,8 +1095,12 @@
         }
         // TODO: We need a better way to get data out of keyframes.
         if (mKeyframes instanceof PathKeyframes.FloatKeyframesBase
-                || mKeyframes instanceof PathKeyframes.IntKeyframesBase) {
-            // property values will animate based on external data source (e.g. Path)
+                || mKeyframes instanceof PathKeyframes.IntKeyframesBase
+                || (mKeyframes.getKeyframes() != null && mKeyframes.getKeyframes().size() > 2)) {
+            // When a pvh has more than 2 keyframes, that means there are intermediate values in
+            // addition to start/end values defined for animators. Another case where such
+            // intermediate values are defined is when animator has a path to animate along. In
+            // these cases, a data source is needed to capture these intermediate values.
             values.dataSource = new PropertyValues.DataSource() {
                 @Override
                 public Object getValueAtFraction(float fraction) {
@@ -1108,6 +1112,13 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public Class getValueType() {
+        return mValueType;
+    }
+
     @Override
     public String toString() {
         return mPropertyName + ": " + mKeyframes.toString();
@@ -1178,6 +1189,15 @@
         }
 
         @Override
+        public void setProperty(Property property) {
+            if (property instanceof IntProperty) {
+                mIntProperty = (IntProperty) property;
+            } else {
+                super.setProperty(property);
+            }
+        }
+
+        @Override
         public void setIntValues(int... values) {
             super.setIntValues(values);
             mIntKeyframes = (Keyframes.IntKeyframes) mKeyframes;
@@ -1316,6 +1336,15 @@
         }
 
         @Override
+        public void setProperty(Property property) {
+            if (property instanceof FloatProperty) {
+                mFloatProperty = (FloatProperty) property;
+            } else {
+                super.setProperty(property);
+            }
+        }
+
+        @Override
         public void setFloatValues(float... values) {
             super.setFloatValues(values);
             mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
@@ -1516,7 +1545,7 @@
                     }
                     propertyMap.put(mPropertyName, mJniSetter);
                 }
-           }
+            }
         }
     }
 
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 4edf249..0c7ee2c 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -602,7 +602,9 @@
         long currentTime = AnimationUtils.currentAnimationTimeMillis();
         mStartTime = currentTime - seekTime;
         mStartTimeCommitted = true; // do not allow start time to be compensated for jank
-        if (!mRunning) {
+        if (!isPulsingInternal()) {
+            // If the animation loop hasn't started, the startTime will be adjusted in the first
+            // frame based on seek fraction.
             mSeekFraction = fraction;
         }
         mOverallFraction = fraction;
@@ -980,6 +982,10 @@
         mStarted = true;
         mPaused = false;
         mRunning = false;
+        // Resets mLastFrameTime when start() is called, so that if the animation was running,
+        // calling start() would put the animation in the
+        // started-but-not-yet-reached-the-first-frame phase.
+        mLastFrameTime = 0;
         AnimationHandler animationHandler = AnimationHandler.getInstance();
         animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));
 
@@ -1095,7 +1101,7 @@
      */
     @Override
     public void reverse() {
-        if (mRunning) {
+        if (isPulsingInternal()) {
             long currentTime = AnimationUtils.currentAnimationTimeMillis();
             long currentPlayTime = currentTime - mStartTime;
             long timeLeft = getScaledDuration() - currentPlayTime;
@@ -1103,6 +1109,7 @@
             mStartTimeCommitted = true; // do not allow start time to be compensated for jank
             mReversing = !mReversing;
         } else if (mStarted) {
+            mReversing = !mReversing;
             end();
         } else {
             start(true);
@@ -1177,6 +1184,15 @@
     }
 
     /**
+     * Internal only: This tracks whether the animation has gotten on the animation loop. Note
+     * this is different than {@link #isRunning()} in that the latter tracks the time after start()
+     * is called (or after start delay if any), which may be before the animation loop starts.
+     */
+    private boolean isPulsingInternal() {
+        return mLastFrameTime > 0;
+    }
+
+    /**
      * Returns the name of this animator for debugging purposes.
      */
     String getNameForTrace() {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index cb17be3..ec8b288 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -57,6 +57,7 @@
 import android.media.AudioManager;
 import android.media.session.MediaController;
 import android.net.Uri;
+import android.os.BadParcelableException;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -5023,13 +5024,18 @@
     @Nullable
     public Uri getReferrer() {
         Intent intent = getIntent();
-        Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
-        if (referrer != null) {
-            return referrer;
-        }
-        String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
-        if (referrerName != null) {
-            return Uri.parse(referrerName);
+        try {
+            Uri referrer = intent.getParcelableExtra(Intent.EXTRA_REFERRER);
+            if (referrer != null) {
+                return referrer;
+            }
+            String referrerName = intent.getStringExtra(Intent.EXTRA_REFERRER_NAME);
+            if (referrerName != null) {
+                return Uri.parse(referrerName);
+            }
+        } catch (BadParcelableException e) {
+            Log.w(TAG, "Cannot read referrer from intent;"
+                    + " intent extras contain unknown custom Parcelable objects");
         }
         if (mReferrer != null) {
             return new Uri.Builder().scheme("android-app").authority(mReferrer).build();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2c2f6c1..0728bdf 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.BackupAgent;
@@ -4578,20 +4580,37 @@
     }
 
     /**
+     * Creates a new Configuration only if override would modify base. Otherwise returns base.
+     * @param base The base configuration.
+     * @param override The update to apply to the base configuration. Can be null.
+     * @return A Configuration representing base with override applied.
+     */
+    private static Configuration createNewConfigAndUpdateIfNotNull(@NonNull Configuration base,
+            @Nullable Configuration override) {
+        if (override == null) {
+            return base;
+        }
+        Configuration newConfig = new Configuration(base);
+        newConfig.updateFrom(override);
+        return newConfig;
+    }
+
+    /**
      * Decides whether to update an Activity's configuration and whether to tell the
      * Activity/Component about it.
      * @param cb The component callback to notify of configuration change.
      * @param activityToken The Activity binder token for which this configuration change happened.
      *                      If the change is global, this is null.
      * @param newConfig The new configuration.
-     * @param overrideConfig The override config that differentiates the Activity's configuration
+     * @param amOverrideConfig The override config that differentiates the Activity's configuration
      *                       from the base global configuration.
+     *                       This is supplied by ActivityManager.
      * @param reportToActivity Notify the Activity of the change.
      */
     private void performConfigurationChanged(ComponentCallbacks2 cb,
                                              IBinder activityToken,
                                              Configuration newConfig,
-                                             Configuration overrideConfig,
+                                             Configuration amOverrideConfig,
                                              boolean reportToActivity) {
         // Only for Activity objects, check that they actually call up to their
         // superclass implementation.  ComponentCallbacks2 is an interface, so
@@ -4605,7 +4624,6 @@
         if ((activity == null) || (activity.mCurrentConfig == null)) {
             shouldChangeConfig = true;
         } else {
-
             // If the new config is the same as the config this Activity
             // is already running with then don't bother calling
             // onConfigurationChanged
@@ -4615,34 +4633,36 @@
             }
         }
 
-        if (DEBUG_CONFIGURATION) {
-            Slog.v(TAG, "Config callback " + cb + ": shouldChangeConfig=" + shouldChangeConfig);
-        }
-
         if (shouldChangeConfig) {
+            // Propagate the configuration change to the Activity and ResourcesManager.
+
+            // ContextThemeWrappers may override the configuration for that context.
+            // We must check and apply any overrides defined.
+            Configuration contextThemeWrapperOverrideConfig = null;
+            if (cb instanceof ContextThemeWrapper) {
+                final ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
+                contextThemeWrapperOverrideConfig = contextThemeWrapper.getOverrideConfiguration();
+            }
+
+            // We only update an Activity's configuration if this is not a global
+            // configuration change. This must also be done before the callback,
+            // or else we violate the contract that the new resources are available
+            // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
             if (activityToken != null) {
-                // We only update an Activity's configuration if this is not a global
-                // configuration change. This must also be done before the callback,
-                // or else we violate the contract that the new resources are available
-                // in {@link ComponentCallbacks2#onConfigurationChanged(Configuration)}.
-                mResourcesManager.updateResourcesForActivity(activityToken, overrideConfig);
+                // Apply the ContextThemeWrapper override if necessary.
+                // NOTE: Make sure the configurations are not modified, as they are treated
+                // as immutable in many places.
+                final Configuration finalOverrideConfig = createNewConfigAndUpdateIfNotNull(
+                        amOverrideConfig, contextThemeWrapperOverrideConfig);
+                mResourcesManager.updateResourcesForActivity(activityToken, finalOverrideConfig);
             }
 
             if (reportToActivity) {
-                Configuration configToReport = newConfig;
-
-                if (cb instanceof ContextThemeWrapper) {
-                    // ContextThemeWrappers may override the configuration for that context.
-                    // We must check and apply any overrides defined.
-                    ContextThemeWrapper contextThemeWrapper = (ContextThemeWrapper) cb;
-                    final Configuration localOverrideConfig =
-                            contextThemeWrapper.getOverrideConfiguration();
-                    if (localOverrideConfig != null) {
-                        configToReport = new Configuration(newConfig);
-                        configToReport.updateFrom(localOverrideConfig);
-                    }
-                }
-
+                // Apply the ContextThemeWrapper override if necessary.
+                // NOTE: Make sure the configurations are not modified, as they are treated
+                // as immutable in many places.
+                final Configuration configToReport = createNewConfigAndUpdateIfNotNull(
+                        newConfig, contextThemeWrapperOverrideConfig);
                 cb.onConfigurationChanged(configToReport);
             }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index e526c17..1e4ffbe 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1340,9 +1340,14 @@
     /** @hide */
     public void setUserRestriction(int code, boolean restricted, IBinder token,
             String[] exceptionPackages) {
+        setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId());
+    }
+
+    /** @hide */
+    public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
+            String[] exceptionPackages, int userId) {
         try {
-            mService.setUserRestriction(code, restricted, token, mContext.getUserId(),
-                  exceptionPackages);
+            mService.setUserRestriction(code, restricted, token, userId, exceptionPackages);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 152f45e..0b62ed2 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -1191,14 +1191,18 @@
 
         public void performReceive(Intent intent, int resultCode, String data,
                 Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
-            if (ActivityThread.DEBUG_BROADCAST) {
-                int seq = intent.getIntExtra("seq", -1);
-                Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction() + " seq=" + seq
-                        + " to " + mReceiver);
-            }
-            Args args = new Args(intent, resultCode, data, extras, ordered,
+            final Args args = new Args(intent, resultCode, data, extras, ordered,
                     sticky, sendingUser);
-            if (!mActivityThread.post(args)) {
+            if (intent == null) {
+                Log.wtf(TAG, "Null intent received");
+            } else {
+                if (ActivityThread.DEBUG_BROADCAST) {
+                    int seq = intent.getIntExtra("seq", -1);
+                    Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+                            + " seq=" + seq + " to " + mReceiver);
+                }
+            }
+            if (intent == null || !mActivityThread.post(args)) {
                 if (mRegistered && ordered) {
                     IActivityManager mgr = ActivityManagerNative.getDefault();
                     if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 83a2066..f896fb5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1986,6 +1986,10 @@
                     new Throwable());
         }
 
+        if (context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+            extras.putBoolean(EXTRA_SHOW_WHEN, true);
+        }
+
         // ensure that any information already set directly is preserved
         final Notification.Builder builder = new Notification.Builder(context, this);
 
@@ -2269,6 +2273,14 @@
                     Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
                 }
 
+                if (mN.getSmallIcon() == null && mN.icon != 0) {
+                    setSmallIcon(mN.icon);
+                }
+
+                if (mN.getLargeIcon() == null && mN.largeIcon != null) {
+                    setLargeIcon(mN.largeIcon);
+                }
+
                 String templateClass = mN.extras.getString(EXTRA_TEMPLATE);
                 if (!TextUtils.isEmpty(templateClass)) {
                     final Class<? extends Style> styleClass
@@ -3171,8 +3183,8 @@
         }
 
         private void resetContentMargins(RemoteViews contentView) {
-            contentView.setViewLayoutMarginEnd(R.id.line1, 0);
-            contentView.setViewLayoutMarginEnd(R.id.text, 0);
+            contentView.setViewLayoutMarginEndDimen(R.id.line1, 0);
+            contentView.setViewLayoutMarginEndDimen(R.id.text, 0);
         }
 
         private RemoteViews applyStandardTemplate(int resId) {
@@ -3266,11 +3278,10 @@
                 contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
                 contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
                 processLargeLegacyIcon(mN.mLargeIcon, contentView);
-                int endMargin = mContext.getResources().getDimensionPixelSize(
-                        R.dimen.notification_content_picture_margin);
-                contentView.setViewLayoutMarginEnd(R.id.line1, endMargin);
-                contentView.setViewLayoutMarginEnd(R.id.text, endMargin);
-                contentView.setViewLayoutMarginEnd(R.id.progress, endMargin);
+                int endMargin = R.dimen.notification_content_picture_margin;
+                contentView.setViewLayoutMarginEndDimen(R.id.line1, endMargin);
+                contentView.setViewLayoutMarginEndDimen(R.id.text, endMargin);
+                contentView.setViewLayoutMarginEndDimen(R.id.progress, endMargin);
             }
         }
 
@@ -3394,6 +3405,8 @@
             big.setTextViewText(R.id.notification_material_reply_text_2, null);
             big.setViewVisibility(R.id.notification_material_reply_text_3, View.GONE);
             big.setTextViewText(R.id.notification_material_reply_text_3, null);
+
+            big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target, 0);
         }
 
         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
@@ -3416,6 +3429,8 @@
             if (N > 0) {
                 big.setViewVisibility(R.id.actions_container, View.VISIBLE);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
+                big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
+                        R.dimen.notification_action_list_height);
                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
                 for (int i=0; i<N; i++) {
                     Action action = mActions.get(i);
@@ -4570,12 +4585,21 @@
                     : mConversationTitle;
             boolean hasTitle = !TextUtils.isEmpty(title);
 
-            if (!hasTitle && mMessages.size() == 1) {
-                CharSequence sender = mMessages.get(0).mSender;
-                CharSequence text = mMessages.get(0).mText;
+            if (mMessages.size() == 1) {
+                // Special case for a single message: Use the big text style
+                // so the collapsed and expanded versions match nicely.
+                CharSequence bigTitle;
+                CharSequence text;
+                if (hasTitle) {
+                    bigTitle = title;
+                    text = makeMessageLine(mMessages.get(0));
+                } else {
+                    bigTitle = mMessages.get(0).mSender;
+                    text = mMessages.get(0).mText;
+                }
                 RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                         mBuilder.getBigTextLayoutResource(),
-                        false /* progress */, sender, null /* text */);
+                        false /* progress */, bigTitle, null /* text */);
                 BigTextStyle.applyBigTextContentView(mBuilder, contentView, text);
                 return contentView;
             }
@@ -4595,12 +4619,13 @@
             }
 
             int i=0;
-            int titlePadding = mBuilder.mContext.getResources().getDimensionPixelSize(
-                    R.dimen.notification_messaging_spacing);
-            contentView.setViewLayoutMarginBottom(R.id.line1, hasTitle ? titlePadding : 0);
+            contentView.setViewLayoutMarginBottomDimen(R.id.line1,
+                    hasTitle ? R.dimen.notification_messaging_spacing : 0);
             contentView.setInt(R.id.notification_messaging, "setNumIndentLines",
                     mBuilder.mN.mLargeIcon == null ? 0 : (hasTitle ? 1 : 2));
 
+            int contractedChildId = View.NO_ID;
+            Message contractedMessage = findLatestIncomingMessage();
             int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
             while (firstMessage + i < mMessages.size() && i < rowIds.length) {
                 Message m = mMessages.get(firstMessage + i);
@@ -4609,8 +4634,15 @@
                 contentView.setViewVisibility(rowId, View.VISIBLE);
                 contentView.setTextViewText(rowId, makeMessageLine(m));
 
+                if (contractedMessage == m) {
+                    contractedChildId = rowId;
+                }
+
                 i++;
             }
+            // Record this here to allow transformation between the contracted and expanded views.
+            contentView.setInt(R.id.notification_messaging, "setContractedChildId",
+                    contractedChildId);
             return contentView;
         }
 
@@ -4964,11 +4996,10 @@
                 final boolean ind = mBuilder.mN.extras.getBoolean(EXTRA_PROGRESS_INDETERMINATE);
                 boolean hasProgress = max != 0 || ind;
                 if (mBuilder.mN.mLargeIcon != null && !hasProgress) {
-                    endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
-                            R.dimen.notification_content_picture_margin);
+                    endMargin = R.dimen.notification_content_picture_margin;
                 }
             }
-            contentView.setViewLayoutMarginEnd(id, endMargin);
+            contentView.setViewLayoutMarginEndDimen(id, endMargin);
         }
     }
 
@@ -5153,13 +5184,11 @@
             }
             handleImage(view);
             // handle the content margin
-            int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
-                    R.dimen.notification_content_margin_end);;
+            int endMargin = R.dimen.notification_content_margin_end;
             if (mBuilder.mN.mLargeIcon != null) {
-                endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
-                        R.dimen.notification_content_picture_margin);
+                endMargin = R.dimen.notification_content_plus_picture_margin_end;
             }
-            view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+            view.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
             return view;
         }
 
@@ -5190,8 +5219,8 @@
 
         private void handleImage(RemoteViews contentView) {
             if (mBuilder.mN.mLargeIcon != null) {
-                contentView.setViewLayoutMarginEnd(R.id.line1, 0);
-                contentView.setViewLayoutMarginEnd(R.id.text, 0);
+                contentView.setViewLayoutMarginEndDimen(R.id.line1, 0);
+                contentView.setViewLayoutMarginEndDimen(R.id.text, 0);
             }
         }
 
@@ -5306,13 +5335,11 @@
                 remoteViews.addView(R.id.notification_main_column, customContent);
             }
             // also update the end margin if there is an image
-            int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
-                    R.dimen.notification_content_margin_end);
+            int endMargin = R.dimen.notification_content_margin_end;
             if (mBuilder.mN.mLargeIcon != null) {
-                endMargin += mBuilder.mContext.getResources().getDimensionPixelSize(
-                        R.dimen.notification_content_picture_margin);
+                endMargin = R.dimen.notification_content_plus_picture_margin_end;
             }
-            remoteViews.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
+            remoteViews.setViewLayoutMarginEndDimen(R.id.notification_main_column, endMargin);
         }
     }
 
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 18f93cd..7f467f0 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1576,8 +1576,11 @@
         final String whichProp;
         final int defaultResId;
         if (which == FLAG_LOCK) {
+            /* Factory-default lock wallpapers are not yet supported
             whichProp = PROP_LOCK_WALLPAPER;
             defaultResId = com.android.internal.R.drawable.default_lock_wallpaper;
+            */
+            return null;
         } else {
             whichProp = PROP_WALLPAPER;
             defaultResId = com.android.internal.R.drawable.default_wallpaper;
diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java
index 54a2f7a..9a0cd56 100644
--- a/core/java/android/app/admin/DevicePolicyManagerInternal.java
+++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java
@@ -17,7 +17,6 @@
 package android.app.admin;
 
 import android.content.Intent;
-import android.os.UserHandle;
 
 import java.util.List;
 
@@ -48,6 +47,8 @@
      * Gets the packages whose widget providers are white-listed to be
      * available in the parent user.
      *
+     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
+     *
      * @param profileId The profile id.
      * @return The list of packages if such or empty list if there are
      *    no white-listed packages or the profile id is not a managed
@@ -59,6 +60,8 @@
      * Adds a listener for changes in the white-listed packages to show
      * cross-profile app widgets.
      *
+     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
+     *
      * @param listener The listener to add.
      */
     public abstract void addOnCrossProfileWidgetProvidersChangeListener(
@@ -67,6 +70,9 @@
     /**
      * Checks if an app with given uid is an active device admin of its user and has the policy
      * specified.
+     *
+     * <p>This takes the DPMS lock.  DO NOT call from PM/UM/AM with their lock held.
+     *
      * @param uid App uid.
      * @param reqPolicy Required policy, for policies see {@link DevicePolicyManager}.
      * @return true if the uid is an active admin with the given policy.
@@ -74,21 +80,12 @@
     public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
 
     /**
-     * Checks if a given package has a device or a profile owner for the given user.
-     * <p>
-     * <em>Note: does <b>not</b> support negative userIds like {@link UserHandle#USER_ALL}</em>
-     *
-     * @param packageName The package to check
-     * @param userId the userId to check for.
-     * @return true if package has a device or profile owner, false otherwise.
-     */
-    public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
-
-    /**
      * Creates an intent to show the admin support dialog to let the user know that the package is
      * suspended by the admin. This assumes that {@param packageName} is suspended by the
      * device/profile owner. The caller should check if the package is suspended or not.
      *
+     * <p>This method does not take the DPMS lock.  Safe to be called from anywhere.
+     *
      * @param packageName The package that is suspended
      * @param userId The user having the suspended package.
      * @return The intent to trigger the admin support dialog.
diff --git a/core/java/android/content/pm/EphemeralResolveInfo.java b/core/java/android/content/pm/EphemeralResolveInfo.java
index afb4c30..b87731b 100644
--- a/core/java/android/content/pm/EphemeralResolveInfo.java
+++ b/core/java/android/content/pm/EphemeralResolveInfo.java
@@ -57,10 +57,10 @@
 
         mDigestBytes = generateDigest(uri);
         mDigestPrefix =
-                mDigestBytes[0] << 24
-                | mDigestBytes[1] << 16
-                | mDigestBytes[2] << 8
-                | mDigestBytes[3] << 0;
+                (mDigestBytes[0] & 0xFF) << 24
+                | (mDigestBytes[1] & 0xFF) << 16
+                | (mDigestBytes[2] & 0xFF) << 8
+                | (mDigestBytes[3] & 0xFF) << 0;
         mFilters.addAll(filters);
         mPackageName = packageName;
     }
diff --git a/core/java/android/content/pm/IOtaDexopt.aidl b/core/java/android/content/pm/IOtaDexopt.aidl
index 8f38d6f..786a77f 100644
--- a/core/java/android/content/pm/IOtaDexopt.aidl
+++ b/core/java/android/content/pm/IOtaDexopt.aidl
@@ -42,6 +42,12 @@
     boolean isDone();
 
     /**
+     * Return the progress (0..1) made in this session. When {@link #isDone() isDone} returns
+     * true, the progress value will be 1.
+     */
+    float getProgress();
+
+    /**
      * Optimize the next package. Note: this command is synchronous, that is, only returns after
      * the package has been dexopted (or dexopting failed).
      */
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 13ebb82..14f7727 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.SparseArray;
 
 import java.util.List;
 
@@ -147,4 +148,16 @@
      */
     public abstract ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
             int userId);
+
+    /**
+     * Called by DeviceOwnerManagerService to set the package names of device owner and profile
+     * owners.
+     */
+    public abstract void setDeviceAndProfileOwnerPackages(
+            int deviceOwnerUserId, String deviceOwner, SparseArray<String> profileOwners);
+
+    /**
+     * Whether a package's data be cleared.
+     */
+    public abstract boolean canPackageBeWiped(int userId, String packageName);
 }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index da58717..094b89d 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -254,9 +254,9 @@
      */
     public void enforceMandatoryFields() {
         Preconditions.checkStringNotEmpty(mId, "Shortcut ID must be provided");
-        Preconditions.checkNotNull(mActivity, "activity must be provided");
+        Preconditions.checkNotNull(mActivity, "Activity must be provided");
         if (mTitle == null && mTitleResId == 0) {
-            throw new IllegalArgumentException("Shortcut title must be provided");
+            throw new IllegalArgumentException("Short label must be provided");
         }
         Preconditions.checkNotNull(mIntent, "Shortcut Intent must be provided");
     }
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index e184d6d..ee8a6d7 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -1644,41 +1644,6 @@
     }
 
     public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {
-        //
-        // Constants below need to be kept up-to-date with
-        // frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
-        //
-
-        //
-        // Error codes for onCameraError
-        //
-
-        /**
-         * Camera has been disconnected
-         */
-        public static final int ERROR_CAMERA_DISCONNECTED = 0;
-        /**
-         * Camera has encountered a device-level error
-         * Matches CameraDevice.StateCallback#ERROR_CAMERA_DEVICE
-         */
-        public static final int ERROR_CAMERA_DEVICE = 1;
-        /**
-         * Camera has encountered a service-level error
-         * Matches CameraDevice.StateCallback#ERROR_CAMERA_SERVICE
-         */
-        public static final int ERROR_CAMERA_SERVICE = 2;
-        /**
-         * Camera has encountered an error processing a single request.
-         */
-        public static final int ERROR_CAMERA_REQUEST = 3;
-        /**
-         * Camera has encountered an error producing metadata for a single capture
-         */
-        public static final int ERROR_CAMERA_RESULT = 4;
-        /**
-         * Camera has encountered an error producing an image buffer for a single capture
-         */
-        public static final int ERROR_CAMERA_BUFFER = 5;
 
         @Override
         public IBinder asBinder() {
@@ -1709,11 +1674,14 @@
                     case ERROR_CAMERA_DEVICE:
                     case ERROR_CAMERA_SERVICE:
                         mInError = true;
+                        final int publicErrorCode = (errorCode == ERROR_CAMERA_DEVICE) ?
+                                StateCallback.ERROR_CAMERA_DEVICE :
+                                StateCallback.ERROR_CAMERA_SERVICE;
                         Runnable r = new Runnable() {
                             @Override
                             public void run() {
                                 if (!CameraDeviceImpl.this.isClosed()) {
-                                    mDeviceCallback.onError(CameraDeviceImpl.this, errorCode);
+                                    mDeviceCallback.onError(CameraDeviceImpl.this, publicErrorCode);
                                 }
                             }
                         };
@@ -2085,7 +2053,7 @@
             public void run() {
                 if (!isClosed()) {
                     mDeviceCallback.onError(CameraDeviceImpl.this,
-                            CameraDeviceCallbacks.ERROR_CAMERA_SERVICE);
+                            StateCallback.ERROR_CAMERA_SERVICE);
                 }
             }
         };
diff --git a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
index ba821e4..1565087 100644
--- a/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
+++ b/core/java/android/hardware/camera2/marshal/MarshalRegistry.java
@@ -37,7 +37,9 @@
      * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
      */
     public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
-        sRegisteredMarshalQueryables.add(queryable);
+        synchronized(sMarshalLock) {
+            sRegisteredMarshalQueryables.add(queryable);
+        }
     }
 
     /**
@@ -54,47 +56,50 @@
      */
     @SuppressWarnings("unchecked")
     public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
-        // TODO: can avoid making a new token each time by code-genning
-        // the list of type tokens and native types from the keys (at the call sites)
-        MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
+        synchronized(sMarshalLock) {
+            // TODO: can avoid making a new token each time by code-genning
+            // the list of type tokens and native types from the keys (at the call sites)
+            MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
 
-        /*
-         * Marshalers are instantiated lazily once they are looked up; successive lookups
-         * will not instantiate new marshalers.
-         */
-        Marshaler<T> marshaler =
-                (Marshaler<T>) sMarshalerMap.get(marshalToken);
-
-        if (sRegisteredMarshalQueryables.size() == 0) {
-            throw new AssertionError("No available query marshalers registered");
-        }
-
-        if (marshaler == null) {
-            // Query each marshaler to see if they support the native/managed type combination
-            for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
-
-                MarshalQueryable<T> castedPotential =
-                        (MarshalQueryable<T>)potentialMarshaler;
-
-                if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
-                    marshaler = castedPotential.createMarshaler(typeToken, nativeType);
-                    break;
-                }
-            }
+            /*
+             * Marshalers are instantiated lazily once they are looked up; successive lookups
+             * will not instantiate new marshalers.
+             */
+            Marshaler<T> marshaler =
+                    (Marshaler<T>) sMarshalerMap.get(marshalToken);
 
             if (marshaler == null) {
-                throw new UnsupportedOperationException(
+
+                if (sRegisteredMarshalQueryables.size() == 0) {
+                    throw new AssertionError("No available query marshalers registered");
+                }
+
+                // Query each marshaler to see if they support the native/managed type combination
+                for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
+
+                    MarshalQueryable<T> castedPotential =
+                            (MarshalQueryable<T>)potentialMarshaler;
+
+                    if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
+                        marshaler = castedPotential.createMarshaler(typeToken, nativeType);
+                        break;
+                    }
+                }
+
+                if (marshaler == null) {
+                    throw new UnsupportedOperationException(
                         "Could not find marshaler that matches the requested " +
-                                "combination of type reference " +
-                                typeToken + " and native type " +
-                                MarshalHelpers.toStringNativeType(nativeType));
+                        "combination of type reference " +
+                        typeToken + " and native type " +
+                        MarshalHelpers.toStringNativeType(nativeType));
+                }
+
+                // Only put when no cached version exists to avoid +0.5ms lookup per call.
+                sMarshalerMap.put(marshalToken, marshaler);
             }
 
-            // Only put when no cached version exists to avoid +0.5ms lookup per call.
-            sMarshalerMap.put(marshalToken, marshaler);
+            return marshaler;
         }
-
-        return marshaler;
     }
 
     private static class MarshalToken<T> {
@@ -125,9 +130,12 @@
         }
     }
 
-    private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
+    // Control access to the static data structures below
+    private static final Object sMarshalLock = new Object();
+
+    private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
             new ArrayList<MarshalQueryable<?>>();
-    private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
+    private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
             new HashMap<MarshalToken<?>, Marshaler<?>>();
 
     private MarshalRegistry() {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index ea5ae32..f4bf3ea 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -176,7 +176,7 @@
     /**
      * Current version of checkin data format.
      */
-    static final String CHECKIN_VERSION = "17";
+    static final String CHECKIN_VERSION = "18";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -2371,6 +2371,20 @@
     };
 
     /**
+     * Return the counter keeping track of the amount of battery discharge while the screen was off,
+     * measured in micro-Ampere-hours. This will be non-zero only if the device's battery has
+     * a coulomb counter.
+     */
+    public abstract LongCounter getDischargeScreenOffCoulombCounter();
+
+    /**
+     * Return the counter keeping track of the amount of battery discharge measured in
+     * micro-Ampere-hours. This will be non-zero only if the device's battery has
+     * a coulomb counter.
+     */
+    public abstract LongCounter getDischargeCoulombCounter();
+
+    /**
      * Return the array of discharge step durations.
      */
     public abstract LevelStepTracker getDischargeLevelStepTracker();
@@ -2805,6 +2819,9 @@
                 rawRealtime, which);
         final int connChanges = getNumConnectivityChange(which);
         final long phoneOnTime = getPhoneOnTime(rawRealtime, which);
+        final long dischargeCount = getDischargeCoulombCounter().getCountLocked(which);
+        final long dischargeScreenOffCount = getDischargeScreenOffCoulombCounter()
+                .getCountLocked(which);
 
         final StringBuilder sb = new StringBuilder(128);
         
@@ -2820,6 +2837,7 @@
                 totalRealtime / 1000, totalUptime / 1000,
                 getStartClockTime(),
                 whichBatteryScreenOffRealtime / 1000, whichBatteryScreenOffUptime / 1000);
+
         
         // Calculate wakelock times across all uids.
         long fullWakeLockTimeTotal = 0;
@@ -2969,12 +2987,14 @@
             dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
                     getDischargeStartLevel()-getDischargeCurrentLevel(),
                     getDischargeStartLevel()-getDischargeCurrentLevel(),
-                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+                    getDischargeAmountScreenOn(), getDischargeAmountScreenOff(),
+                    dischargeCount / 1000, dischargeScreenOffCount / 1000);
         } else {
             dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
                     getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
                     getDischargeAmountScreenOnSinceCharge(),
-                    getDischargeAmountScreenOffSinceCharge());
+                    getDischargeAmountScreenOffSinceCharge(),
+                    dischargeCount / 1000, dischargeScreenOffCount / 1000);
         }
         
         if (reqUid < 0) {
@@ -3371,6 +3391,39 @@
                     formatTimeMs(sb, chargeTimeRemaining / 1000);
             pw.println(sb.toString());
         }
+
+        final LongCounter dischargeCounter = getDischargeCoulombCounter();
+        final long dischargeCount = dischargeCounter.getCountLocked(which);
+        if (dischargeCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
+        final LongCounter dischargeScreenOffCounter = getDischargeScreenOffCoulombCounter();
+        final long dischargeScreenOffCount = dischargeScreenOffCounter.getCountLocked(which);
+        if (dischargeScreenOffCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Screen off discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeScreenOffCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
+        final long dischargeScreenOnCount = dischargeCount - dischargeScreenOffCount;
+        if (dischargeScreenOnCount >= 0) {
+            sb.setLength(0);
+            sb.append(prefix);
+                sb.append("  Screen on discharge: ");
+                sb.append(BatteryStatsHelper.makemAh(dischargeScreenOnCount / 1000.0));
+                sb.append(" mAh");
+            pw.println(sb.toString());
+        }
+
         pw.print("  Start clock time: ");
         pw.println(DateFormat.format("yyyy-MM-dd-HH-mm-ss", getStartClockTime()).toString());
 
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index d5491d3..7702c17 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -864,6 +864,34 @@
                 super.close();
             }
         }
+
+        @Override
+        public int read() throws IOException {
+            final int result = super.read();
+            if (result == -1 && mPfd.canDetectErrors()) {
+                // Check for errors only on EOF, to minimize overhead.
+                mPfd.checkError();
+            }
+            return result;
+        }
+
+        @Override
+        public int read(byte[] b) throws IOException {
+            final int result = super.read(b);
+            if (result == -1 && mPfd.canDetectErrors()) {
+                mPfd.checkError();
+            }
+            return result;
+        }
+
+        @Override
+        public int read(byte[] b, int off, int len) throws IOException {
+            final int result = super.read(b, off, len);
+            if (result == -1 && mPfd.canDetectErrors()) {
+                mPfd.checkError();
+            }
+            return result;
+        }
     }
 
     /**
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 83a3bd8..b3cc438 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -662,6 +662,31 @@
     }
 
     /**
+     * Reboot into recovery and wipe the A/B device.
+     *
+     * @param Context      the Context to use.
+     * @param packageFile  the wipe package to be applied.
+     * @param reason       the reason to wipe.
+     *
+     * @throws IOException if something goes wrong.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static void rebootWipeAb(Context context, File packageFile, String reason)
+            throws IOException {
+        String reasonArg = null;
+        if (!TextUtils.isEmpty(reason)) {
+            reasonArg = "--reason=" + sanitizeArg(reason);
+        }
+
+        final String filename = packageFile.getCanonicalPath();
+        final String filenameArg = "--wipe_package=" + filename;
+        final String localeArg = "--locale=" + Locale.getDefault().toString();
+        bootCommand(context, "--wipe_ab", filenameArg, reasonArg, localeArg);
+    }
+
+    /**
      * Reboot into the recovery system with the supplied argument.
      * @param args to pass to the recovery utility.
      * @throws IOException if something goes wrong.
@@ -699,6 +724,7 @@
             String line = null;
             int bytesWrittenInMiB = -1, bytesStashedInMiB = -1;
             int timeTotal = -1;
+            int sourceVersion = -1;
             while ((line = in.readLine()) != null) {
                 // Here is an example of lines in last_install:
                 // ...
@@ -733,6 +759,8 @@
 
                 if (line.startsWith("time")) {
                     timeTotal = scaled;
+                } else if (line.startsWith("source_version")) {
+                    sourceVersion = scaled;
                 } else if (line.startsWith("bytes_written")) {
                     bytesWrittenInMiB = (bytesWrittenInMiB == -1) ? scaled :
                             bytesWrittenInMiB + scaled;
@@ -746,6 +774,9 @@
             if (timeTotal != -1) {
                 MetricsLogger.histogram(context, "ota_time_total", timeTotal);
             }
+            if (sourceVersion != -1) {
+                MetricsLogger.histogram(context, "ota_source_version", sourceVersion);
+            }
             if (bytesWrittenInMiB != -1) {
                 MetricsLogger.histogram(context, "ota_written_in_MiBs", bytesWrittenInMiB);
             }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ec5f45d..43eb751 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6246,6 +6246,21 @@
                 "automatic_storage_manager_enabled";
 
         /**
+         * How many days of information for the automatic storage manager to retain on the device.
+         *
+         * @hide
+         */
+        public static final String AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN =
+                "automatic_storage_manager_days_to_retain";
+
+        /**
+         * Default number of days of information for the automatic storage manager to retain.
+         *
+         * @hide
+         */
+        public static final int AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT = 90;
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
diff --git a/core/java/android/security/net/config/SystemCertificateSource.java b/core/java/android/security/net/config/SystemCertificateSource.java
index abef7b4..cfb195b 100644
--- a/core/java/android/security/net/config/SystemCertificateSource.java
+++ b/core/java/android/security/net/config/SystemCertificateSource.java
@@ -25,7 +25,10 @@
  * @hide
  */
 public final class SystemCertificateSource extends DirectoryCertificateSource {
-    private static final SystemCertificateSource INSTANCE = new SystemCertificateSource();
+    private static class NoPreloadHolder {
+        private static final SystemCertificateSource INSTANCE = new SystemCertificateSource();
+    }
+
     private final File mUserRemovedCaDir;
 
     private SystemCertificateSource() {
@@ -35,7 +38,7 @@
     }
 
     public static SystemCertificateSource getInstance() {
-        return INSTANCE;
+        return NoPreloadHolder.INSTANCE;
     }
 
     @Override
diff --git a/core/java/android/security/net/config/UserCertificateSource.java b/core/java/android/security/net/config/UserCertificateSource.java
index 1a7d924..d6e2b3a 100644
--- a/core/java/android/security/net/config/UserCertificateSource.java
+++ b/core/java/android/security/net/config/UserCertificateSource.java
@@ -25,7 +25,9 @@
  * @hide
  */
 public final class UserCertificateSource extends DirectoryCertificateSource {
-    private static final UserCertificateSource INSTANCE = new UserCertificateSource();
+    private static class NoPreloadHolder {
+        private static final UserCertificateSource INSTANCE = new UserCertificateSource();
+    }
 
     private UserCertificateSource() {
         super(new File(
@@ -33,7 +35,7 @@
     }
 
     public static UserCertificateSource getInstance() {
-        return INSTANCE;
+        return NoPreloadHolder.INSTANCE;
     }
 
     @Override
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index ab4cbcf..0164fcd 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -793,12 +793,12 @@
         return mOwningView != null && mOwningView.mAttachInfo != null;
     }
 
-    public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
+    public void registerVectorDrawableAnimator(
+            AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) {
         if (mOwningView == null || mOwningView.mAttachInfo == null) {
             throw new IllegalStateException("Cannot start this animator on a detached view!");
         }
-        nAddAnimator(mNativeRenderNode, animatorSet.getAnimatorNativePtr());
-        mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
+        mOwningView.mAttachInfo.mViewRootImpl.registerVectorDrawableAnimator(animatorSet);
     }
 
     public void endAllAnimators() {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index e650d95..fcca739 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -23,6 +23,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -881,6 +882,12 @@
         nRegisterAnimatingRenderNode(mRootNode.mNativeRenderNode, animator.mNativeRenderNode);
     }
 
+    void registerVectorDrawableAnimator(
+        AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+        nRegisterVectorDrawableAnimator(mRootNode.mNativeRenderNode,
+                animator.getAnimatorNativePtr());
+    }
+
     public void serializeDisplayListTree() {
         nSerializeDisplayListTree(mNativeProxy);
     }
@@ -992,6 +999,7 @@
     private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
     private static native void nDestroy(long nativeProxy, long rootRenderNode);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
+    private static native void nRegisterVectorDrawableAnimator(long rootRenderNode, long animator);
 
     private static native void nInvokeFunctor(long functor, boolean waitForCompletion);
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 88605db..5f6ee09 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -20538,6 +20538,10 @@
         if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "startDragAndDrop: data=" + data + " flags=" + flags);
         }
+        if (mAttachInfo == null) {
+            Log.w(VIEW_LOG_TAG, "startDragAndDrop called on a detached view.");
+            return false;
+        }
         boolean okay = false;
 
         Point shadowSize = new Point();
@@ -20614,6 +20618,10 @@
         if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "cancelDragAndDrop");
         }
+        if (mAttachInfo == null) {
+            Log.w(VIEW_LOG_TAG, "cancelDragAndDrop called on a detached view.");
+            return;
+        }
         if (mAttachInfo.mDragToken != null) {
             try {
                 mAttachInfo.mSession.cancelDragAndDrop(mAttachInfo.mDragToken);
@@ -20636,6 +20644,10 @@
         if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "updateDragShadow");
         }
+        if (mAttachInfo == null) {
+            Log.w(VIEW_LOG_TAG, "updateDragShadow called on a detached view.");
+            return;
+        }
         if (mAttachInfo.mDragToken != null) {
             try {
                 Canvas canvas = mAttachInfo.mDragSurface.lockCanvas(null);
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 4742818..65f0caa 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -42,6 +42,7 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Region;
+import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManager.DisplayListener;
@@ -824,6 +825,13 @@
         }
     }
 
+    public void registerVectorDrawableAnimator(
+            AnimatedVectorDrawable.VectorDrawableAnimatorRT animator) {
+        if (mAttachInfo.mHardwareRenderer != null) {
+            mAttachInfo.mHardwareRenderer.registerVectorDrawableAnimator(animator);
+        }
+    }
+
     private void enableHardwareAcceleration(WindowManager.LayoutParams attrs) {
         mAttachInfo.mHardwareAccelerated = false;
         mAttachInfo.mHardwareAccelerationRequested = false;
@@ -1938,7 +1946,7 @@
                 mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
                 mSurfaceHolder.mSurfaceLock.unlock();
                 if (mSurface.isValid()) {
-                    if (!hadSurface || surfaceGenerationId != mSurface.getGenerationId()) {
+                    if (!hadSurface) {
                         mSurfaceHolder.ungetCallbacks();
 
                         mIsCreating = true;
@@ -1951,7 +1959,7 @@
                         }
                         surfaceChanged = true;
                     }
-                    if (surfaceChanged) {
+                    if (surfaceChanged || surfaceGenerationId != mSurface.getGenerationId()) {
                         mSurfaceHolderCallback.surfaceChanged(mSurfaceHolder,
                                 lp.format, mWidth, mHeight);
                         SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
index d0d4507..52f35de 100644
--- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java
@@ -16,6 +16,7 @@
 
 package android.view.accessibility;
 
+import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -101,8 +102,9 @@
     /**
      * Gets the title of the window.
      *
-     * @return The title.
+     * @return The title of the window, or {@code null} if none is available.
      */
+    @Nullable
     public CharSequence getTitle() {
         return mTitle;
     }
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index 89dec2d..7c3fc8b 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -851,4 +851,9 @@
         
         endBatchEdit();
     }
+
+    /**
+     * The default implementation does nothing.
+     */
+    public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) { return false; }
 }
diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java
index 7b7ccae..7ed0d27 100644
--- a/core/java/android/view/inputmethod/EditorInfo.java
+++ b/core/java/android/view/inputmethod/EditorInfo.java
@@ -25,6 +25,8 @@
 import android.text.TextUtils;
 import android.util.Printer;
 
+import java.util.Arrays;
+
 /**
  * An EditorInfo describes several attributes of a text editing object
  * that an input method is communicating with (typically an EditText), most
@@ -363,6 +365,18 @@
     @Nullable
     public LocaleList hintLocales = null;
 
+
+    /**
+     * List of acceptable MIME types for
+     * {@link InputConnection#insertContent(InputContentInfo, Bundle)}.
+     *
+     * <p>{@code null} or an empty array means that
+     * {@link InputConnection#insertContent(InputContentInfo, Bundle)} is not supported in this
+     * editor.</p>
+     */
+    @Nullable
+    public String[] contentMimeTypes = null;
+
     /**
      * Ensure that the data in this EditorInfo is compatible with an application
      * that was developed against the given target API version.  This can
@@ -418,6 +432,7 @@
                 + " fieldName=" + fieldName);
         pw.println(prefix + "extras=" + extras);
         pw.println(prefix + "hintLocales=" + hintLocales);
+        pw.println(prefix + "contentMimeTypes=" + Arrays.toString(contentMimeTypes));
     }
 
     /**
@@ -446,6 +461,7 @@
         } else {
             LocaleList.getEmptyLocaleList().writeToParcel(dest, flags);
         }
+        dest.writeStringArray(contentMimeTypes);
     }
 
     /**
@@ -471,6 +487,7 @@
                     res.extras = source.readBundle();
                     LocaleList hintLocales = LocaleList.CREATOR.createFromParcel(source);
                     res.hintLocales = hintLocales.isEmpty() ? null : hintLocales;
+                    res.contentMimeTypes = source.readStringArray();
                     return res;
                 }
 
diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java
index 9f66429..05e0569 100644
--- a/core/java/android/view/inputmethod/InputConnection.java
+++ b/core/java/android/view/inputmethod/InputConnection.java
@@ -16,6 +16,8 @@
 
 package android.view.inputmethod;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.Handler;
 import android.view.KeyCharacterMap;
@@ -836,4 +838,33 @@
      * <p>Note: This does nothing when called from input methods.</p>
      */
     public void closeConnection();
+
+    /**
+     * Called by the input method to insert a content such as PNG image to the editor.
+     *
+     * <p>In order to avoid variety of compatibility issues, this focuses on a simple use case,
+     * where we expect editors and IMEs work cooperatively as follows:</p>
+     * <ul>
+     *     <li>Editor must keep {@link EditorInfo#contentMimeTypes} to be {@code null} if it does
+     *     not support this method at all.</li>
+     *     <li>Editor can ignore this request when the MIME type specified in
+     *     {@code inputContentInfo} does not match to any of {@link EditorInfo#contentMimeTypes}.
+     *     </li>
+     *     <li>Editor can ignore the cursor position when inserting the provided context.</li>
+     *     <li>Editor can return {@code true} asynchronously, even before it starts loading the
+     *     content.</li>
+     *     <li>Editor should provide a way to delete the content inserted by this method, or revert
+     *     the effect caused by this method.</li>
+     *     <li>IME should not call this method when there is any composing text, in case calling
+     *     this method causes focus change.</li>
+     *     <li>IME should grant a permission for the editor to read the content. See
+     *     {@link EditorInfo#packageName} about how to obtain the package name of the editor.</li>
+     * </ul>
+     *
+     * @param inputContentInfo Content to be inserted.
+     * @param opts optional bundle data. This can be {@code null}.
+     * @return {@code true} if this request is accepted by the application, no matter if the request
+     * is already handled or still being handled in background.
+     */
+    public boolean insertContent(@NonNull InputContentInfo inputContentInfo, @Nullable Bundle opts);
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionInspector.java b/core/java/android/view/inputmethod/InputConnectionInspector.java
index 118a61f..fb24fcd 100644
--- a/core/java/android/view/inputmethod/InputConnectionInspector.java
+++ b/core/java/android/view/inputmethod/InputConnectionInspector.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Bundle;
 
 import java.lang.annotation.Retention;
 import java.lang.reflect.Method;
@@ -41,6 +42,8 @@
             MissingMethodFlags.REQUEST_CURSOR_UPDATES,
             MissingMethodFlags.DELETE_SURROUNDING_TEXT_IN_CODE_POINTS,
             MissingMethodFlags.GET_HANDLER,
+            MissingMethodFlags.CLOSE_CONNECTION,
+            MissingMethodFlags.INSERT_CONTENT,
     })
     public @interface MissingMethodFlags {
         /**
@@ -78,6 +81,11 @@
          * {@link android.os.Build.VERSION_CODES#N} and later.
          */
         int CLOSE_CONNECTION = 1 << 6;
+        /**
+         * {@link InputConnection#insertContent(InputContentInfo, Bundle)} is available in
+         * {@link android.os.Build.VERSION_CODES#N} MR-1 and later.
+         */
+        int INSERT_CONTENT = 1 << 7;
     }
 
     private static final Map<Class, Integer> sMissingMethodsMap = Collections.synchronizedMap(
@@ -127,6 +135,9 @@
         if (!hasCloseConnection(clazz)) {
             flags |= MissingMethodFlags.CLOSE_CONNECTION;
         }
+        if (!hasInsertContent(clazz)) {
+            flags |= MissingMethodFlags.INSERT_CONTENT;
+        }
         sMissingMethodsMap.put(clazz, flags);
         return flags;
     }
@@ -195,6 +206,16 @@
         }
     }
 
+    private static boolean hasInsertContent(@NonNull final Class clazz) {
+        try {
+            final Method method = clazz.getMethod("insertContent", InputContentInfo.class,
+                    Bundle.class);
+            return !Modifier.isAbstract(method.getModifiers());
+        } catch (NoSuchMethodException e) {
+            return false;
+        }
+    }
+
     public static String getMissingMethodFlagsAsString(@MissingMethodFlags final int flags) {
         final StringBuilder sb = new StringBuilder();
         boolean isEmpty = true;
@@ -242,6 +263,12 @@
             }
             sb.append("closeConnection()");
         }
+        if ((flags & MissingMethodFlags.INSERT_CONTENT) != 0) {
+            if (!isEmpty) {
+                sb.append(",");
+            }
+            sb.append("InsertContent(InputContentInfo, Bundle)");
+        }
         return sb.toString();
     }
 }
diff --git a/core/java/android/view/inputmethod/InputConnectionWrapper.java b/core/java/android/view/inputmethod/InputConnectionWrapper.java
index e743f62..431836a 100644
--- a/core/java/android/view/inputmethod/InputConnectionWrapper.java
+++ b/core/java/android/view/inputmethod/InputConnectionWrapper.java
@@ -269,4 +269,12 @@
     public void closeConnection() {
         mTarget.closeConnection();
     }
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
+    public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
+        return mTarget.insertContent(inputContentInfo, opts);
+    }
 }
diff --git a/core/java/android/view/inputmethod/InputContentInfo.aidl b/core/java/android/view/inputmethod/InputContentInfo.aidl
new file mode 100644
index 0000000..1afeee3b
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputContentInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.inputmethod;
+
+parcelable InputContentInfo;
diff --git a/core/java/android/view/inputmethod/InputContentInfo.java b/core/java/android/view/inputmethod/InputContentInfo.java
new file mode 100644
index 0000000..e2ecfae
--- /dev/null
+++ b/core/java/android/view/inputmethod/InputContentInfo.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.inputmethod;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ClipDescription;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.security.InvalidParameterException;
+
+/**
+ * A container object with which input methods can send content files to the target application.
+ */
+public class InputContentInfo implements Parcelable {
+
+    @NonNull
+    private final Uri mContentUri;
+    @NonNull
+    private final ClipDescription mDescription;
+    @Nullable
+    private final Uri mLinkUri;
+
+    /**
+     * Constructs {@link InputContentInfo} object only with mandatory data.
+     *
+     * @param contentUri Content URI to be exported from the input method.
+     * This cannot be {@code null}.
+     * @param description A {@link ClipDescription} object that contains the metadata of
+     * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+     * {@link ClipDescription#getLabel()} should be describing the content specified by
+     * {@code contentUri} for accessibility reasons.
+     */
+    public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description) {
+        this(contentUri, description, null /* link Uri */);
+    }
+
+    /**
+     * Constructs {@link InputContentInfo} object with additional link URI.
+     *
+     * @param contentUri Content URI to be exported from the input method.
+     * This cannot be {@code null}.
+     * @param description A {@link ClipDescription} object that contains the metadata of
+     * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+     * {@link ClipDescription#getLabel()} should be describing the content specified by
+     * {@code contentUri} for accessibility reasons.
+     * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
+     * a way to navigate the user to the specified web page if this is not {@code null}.
+     * @throws InvalidParameterException if any invalid parameter is specified.
+     */
+    public InputContentInfo(@NonNull Uri contentUri, @NonNull ClipDescription description,
+            @Nullable Uri linkUri) {
+        validateInternal(contentUri, description, linkUri, true /* throwException */);
+        mContentUri = contentUri;
+        mDescription = description;
+        mLinkUri = linkUri;
+    }
+
+    /**
+     * @return {@code true} if all the fields are valid.
+     * @hide
+     */
+    public boolean validate() {
+        return validateInternal(mContentUri, mDescription, mLinkUri, false /* throwException */);
+    }
+
+    /**
+     * Constructs {@link InputContentInfo} object with additional link URI.
+     *
+     * @param contentUri Content URI to be exported from the input method.
+     * This cannot be {@code null}.
+     * @param description A {@link ClipDescription} object that contains the metadata of
+     * {@code contentUri} such as MIME type(s). This object cannot be {@code null}. Also
+     * {@link ClipDescription#getLabel()} should be describing the content specified by
+     * {@code contentUri} for accessibility reasons.
+     * @param linkUri An optional {@code http} or {@code https} URI. The editor author may provide
+     * a way to navigate the user to the specified web page if this is not {@code null}.
+     * @param throwException {@code true} if this method should throw an
+     * {@link InvalidParameterException}.
+     * @throws InvalidParameterException if any invalid parameter is specified.
+     */
+    private static boolean validateInternal(@NonNull Uri contentUri,
+            @NonNull ClipDescription description, @Nullable Uri linkUri, boolean throwException) {
+        if (contentUri == null) {
+            if (throwException) {
+                throw new NullPointerException("contentUri");
+            }
+            return false;
+        }
+        if (description == null) {
+            if (throwException) {
+                throw new NullPointerException("description");
+            }
+            return false;
+        }
+        final String contentUriScheme = contentUri.getScheme();
+        if (contentUriScheme == null || !contentUriScheme.equalsIgnoreCase("content")) {
+            if (throwException) {
+                throw new InvalidParameterException("contentUri must have content scheme");
+            }
+            return false;
+        }
+        if (linkUri != null) {
+            final String scheme = linkUri.getScheme();
+            if (scheme == null ||
+                    (!scheme.equalsIgnoreCase("http") && !scheme.equalsIgnoreCase("https"))) {
+                if (throwException) {
+                    throw new InvalidParameterException(
+                            "linkUri must have either http or https scheme");
+                }
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * @return Content URI with which the content can be obtained.
+     */
+    @NonNull
+    public Uri getContentUri() { return mContentUri; }
+
+    /**
+     * @return {@link ClipDescription} object that contains the metadata of {@code contentUri} such
+     * as MIME type(s). {@link ClipDescription#getLabel()} can be used for accessibility purpose.
+     */
+    @NonNull
+    public ClipDescription getDescription() { return mDescription; }
+
+    /**
+     * @return An optional {@code http} or {@code https} URI that is related to this content.
+     */
+    @Nullable
+    public Uri getLinkUri() { return mLinkUri; }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        Uri.writeToParcel(dest, mContentUri);
+        mDescription.writeToParcel(dest, flags);
+        Uri.writeToParcel(dest, mLinkUri);
+    }
+
+    private InputContentInfo(@NonNull Parcel source) {
+        mContentUri = Uri.CREATOR.createFromParcel(source);
+        mDescription = ClipDescription.CREATOR.createFromParcel(source);
+        mLinkUri = Uri.CREATOR.createFromParcel(source);
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<InputContentInfo> CREATOR
+            = new Parcelable.Creator<InputContentInfo>() {
+        @Override
+        public InputContentInfo createFromParcel(Parcel source) {
+            return new InputContentInfo(source);
+        }
+
+        @Override
+        public InputContentInfo[] newArray(int size) {
+            return new InputContentInfo[size];
+        }
+    };
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index b331be7..fb532e2 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -19,6 +19,7 @@
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.NonNull;
+import android.content.ClipData;
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.TypedArray;
@@ -75,6 +76,7 @@
 import android.view.inputmethod.ExtractedText;
 import android.view.inputmethod.ExtractedTextRequest;
 import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputContentInfo;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.RemoteViews.OnClickHandler;
 
@@ -5982,6 +5984,11 @@
         public void closeConnection() {
             getTarget().closeConnection();
         }
+
+        @Override
+        public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
+            return getTarget().insertContent(inputContentInfo, opts);
+        }
     }
 
     /**
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 4a0f350..c33288b 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -17,6 +17,7 @@
 package android.widget;
 
 import android.annotation.ColorInt;
+import android.annotation.DimenRes;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityOptions;
 import android.app.ActivityThread;
@@ -1850,13 +1851,13 @@
     /**
      * Helper action to set layout params on a View.
      */
-    private class LayoutParamAction extends Action {
+    private static class LayoutParamAction extends Action {
 
         /** Set marginEnd */
-        public static final int LAYOUT_MARGIN_END = 1;
+        public static final int LAYOUT_MARGIN_END_DIMEN = 1;
         /** Set width */
         public static final int LAYOUT_WIDTH = 2;
-        public static final int LAYOUT_MARGIN_BOTTOM = 3;
+        public static final int LAYOUT_MARGIN_BOTTOM_DIMEN = 3;
 
         /**
          * @param viewId ID of the view alter
@@ -1893,15 +1894,17 @@
                 return;
             }
             switch (property) {
-                case LAYOUT_MARGIN_END:
+                case LAYOUT_MARGIN_END_DIMEN:
                     if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
-                        ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(value);
+                        int resolved = resolveDimenPixelOffset(target, value);
+                        ((ViewGroup.MarginLayoutParams) layoutParams).setMarginEnd(resolved);
                         target.setLayoutParams(layoutParams);
                     }
                     break;
-                case LAYOUT_MARGIN_BOTTOM:
+                case LAYOUT_MARGIN_BOTTOM_DIMEN:
                     if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
-                        ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = value;
+                        int resolved = resolveDimenPixelOffset(target, value);
+                        ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin = resolved;
                         target.setLayoutParams(layoutParams);
                     }
                     break;
@@ -1914,6 +1917,13 @@
             }
         }
 
+        private static int resolveDimenPixelOffset(View target, int value) {
+            if (value == 0) {
+                return 0;
+            }
+            return target.getContext().getResources().getDimensionPixelOffset(value);
+        }
+
         public String getActionName() {
             return "LayoutParamAction" + property + ".";
         }
@@ -2870,27 +2880,36 @@
      * Hidden for now since we don't want to support this for all different layout margins yet.
      *
      * @param viewId The id of the view to change
-     * @param endMargin the left padding in pixels
+     * @param endMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
      */
-    public void setViewLayoutMarginEnd(int viewId, int endMargin) {
-        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END, endMargin));
+    public void setViewLayoutMarginEndDimen(int viewId, @DimenRes int endMarginDimen) {
+        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_END_DIMEN,
+                endMarginDimen));
     }
 
     /**
      * Equivalent to setting {@link android.view.ViewGroup.MarginLayoutParams#bottomMargin}.
      *
+     * @param bottomMarginDimen a dimen resource to read the margin from or 0 to clear the margin.
      * @hide
      */
-    public void setViewLayoutMarginBottom(int viewId, int bottomMargin) {
-        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM,
-                bottomMargin));
+    public void setViewLayoutMarginBottomDimen(int viewId, @DimenRes int bottomMarginDimen) {
+        addAction(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_MARGIN_BOTTOM_DIMEN,
+                bottomMarginDimen));
     }
 
     /**
      * Equivalent to setting {@link android.view.ViewGroup.LayoutParams#width}.
+     *
+     * @param layoutWidth one of 0, MATCH_PARENT or WRAP_CONTENT. Other sizes are not allowed
+     *                    because they behave poorly when the density changes.
      * @hide
      */
     public void setViewLayoutWidth(int viewId, int layoutWidth) {
+        if (layoutWidth != 0 && layoutWidth != ViewGroup.LayoutParams.MATCH_PARENT
+                && layoutWidth != ViewGroup.LayoutParams.WRAP_CONTENT) {
+            throw new IllegalArgumentException("Only supports 0, WRAP_CONTENT and MATCH_PARENT");
+        }
         mActions.add(new LayoutParamAction(viewId, LayoutParamAction.LAYOUT_WIDTH, layoutWidth));
     }
 
diff --git a/core/java/com/android/internal/app/AlertController.java b/core/java/com/android/internal/app/AlertController.java
index c5ed29f..2a40aeb 100644
--- a/core/java/com/android/internal/app/AlertController.java
+++ b/core/java/com/android/internal/app/AlertController.java
@@ -24,6 +24,7 @@
 import android.app.AlertDialog;
 import android.content.Context;
 import android.content.DialogInterface;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.database.Cursor;
 import android.graphics.drawable.Drawable;
@@ -177,6 +178,11 @@
         return outValue.data != 0;
     }
 
+    private static boolean isWatch(Context context) {
+        return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_WATCH)
+                == Configuration.UI_MODE_TYPE_WATCH;
+    }
+
     public static final AlertController create(Context context, DialogInterface di, Window window) {
         final TypedArray a = context.obtainStyledAttributes(
                 null, R.styleable.AlertDialog, R.attr.alertDialogStyle, 0);
@@ -886,8 +892,14 @@
             listView.setAdapter(mAdapter);
             final int checkedItem = mCheckedItem;
             if (checkedItem > -1) {
-                listView.setItemChecked(checkedItem + listView.getHeaderViewsCount(), true);
-                listView.setSelection(checkedItem + listView.getHeaderViewsCount());
+                // TODO: Remove temp watch specific code
+                if (isWatch(mContext)) {
+                    listView.setItemChecked(checkedItem + listView.getHeaderViewsCount(), true);
+                    listView.setSelection(checkedItem + listView.getHeaderViewsCount());
+                } else {
+                    listView.setItemChecked(checkedItem, true);
+                    listView.setSelection(checkedItem);
+                }
             }
         }
     }
@@ -1066,8 +1078,13 @@
                             if (mCheckedItems != null) {
                                 boolean isItemChecked = mCheckedItems[position];
                                 if (isItemChecked) {
-                                    listView.setItemChecked(
-                                            position + listView.getHeaderViewsCount(), true);
+                                    // TODO: Remove temp watch specific code
+                                    if (isWatch(mContext)) {
+                                        listView.setItemChecked(
+                                                position + listView.getHeaderViewsCount(), true);
+                                    } else {
+                                        listView.setItemChecked(position, true);
+                                    }
                                 }
                             }
                             return view;
@@ -1088,9 +1105,16 @@
                         public void bindView(View view, Context context, Cursor cursor) {
                             CheckedTextView text = (CheckedTextView) view.findViewById(R.id.text1);
                             text.setText(cursor.getString(mLabelIndex));
-                            listView.setItemChecked(
-                                    cursor.getPosition() + listView.getHeaderViewsCount(),
-                                    cursor.getInt(mIsCheckedIndex) == 1);
+                            // TODO: Remove temp watch specific code
+                            if (isWatch(mContext)) {
+                                listView.setItemChecked(
+                                        cursor.getPosition() + listView.getHeaderViewsCount(),
+                                        cursor.getInt(mIsCheckedIndex) == 1);
+                            } else {
+                                listView.setItemChecked(
+                                        cursor.getPosition(),
+                                        cursor.getInt(mIsCheckedIndex) == 1);
+                            }
                         }
 
                         @Override
@@ -1133,7 +1157,10 @@
                 listView.setOnItemClickListener(new OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
-                        position -= listView.getHeaderViewsCount();
+                        // TODO: Remove temp watch specific code
+                        if (isWatch(mContext)) {
+                            position -= listView.getHeaderViewsCount();
+                        }
                         mOnClickListener.onClick(dialog.mDialogInterface, position);
                         if (!mIsSingleChoice) {
                             dialog.mDialogInterface.dismiss();
@@ -1144,7 +1171,10 @@
                 listView.setOnItemClickListener(new OnItemClickListener() {
                     @Override
                     public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
-                        position -= listView.getHeaderViewsCount();
+                        // TODO: Remove temp watch specific code
+                        if (isWatch(mContext)) {
+                            position -= listView.getHeaderViewsCount();
+                        }
                         if (mCheckedItems != null) {
                             mCheckedItems[position] = listView.isItemChecked(position);
                         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 8b02352..07d38d7 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 144 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 146 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -509,6 +509,9 @@
     int mDischargeAmountScreenOff;
     int mDischargeAmountScreenOffSinceCharge;
 
+    private LongSamplingCounter mDischargeScreenOffCounter;
+    private LongSamplingCounter mDischargeCounter;
+
     static final int MAX_LEVEL_STEPS = 200;
 
     int mInitStepMode = 0;
@@ -565,6 +568,16 @@
         return mWakeupReasonStats;
     }
 
+    @Override
+    public LongCounter getDischargeScreenOffCoulombCounter() {
+        return mDischargeScreenOffCounter;
+    }
+
+    @Override
+    public LongCounter getDischargeCoulombCounter() {
+        return mDischargeCounter;
+    }
+
     public BatteryStatsImpl() {
         this(new SystemClocks());
     }
@@ -912,7 +925,6 @@
         final TimeBase mTimeBase;
         long mCount;
         long mLoadedCount;
-        long mLastCount;
         long mUnpluggedCount;
         long mPluggedCount;
 
@@ -921,7 +933,6 @@
             mPluggedCount = in.readLong();
             mCount = mPluggedCount;
             mLoadedCount = in.readLong();
-            mLastCount = 0;
             mUnpluggedCount = in.readLong();
             timeBase.add(this);
         }
@@ -949,20 +960,19 @@
         }
 
         public long getCountLocked(int which) {
-            long val = mCount;
+            long val = mTimeBase.isRunning() ? mCount : mPluggedCount;
             if (which == STATS_SINCE_UNPLUGGED) {
                 val -= mUnpluggedCount;
             } else if (which != STATS_SINCE_CHARGED) {
                 val -= mLoadedCount;
             }
-
             return val;
         }
 
         @Override
         public void logState(Printer pw, String prefix) {
             pw.println(prefix + "mCount=" + mCount
-                    + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount
+                    + " mLoadedCount=" + mLoadedCount
                     + " mUnpluggedCount=" + mUnpluggedCount
                     + " mPluggedCount=" + mPluggedCount);
         }
@@ -976,7 +986,7 @@
          */
         void reset(boolean detachIfReset) {
             mCount = 0;
-            mLoadedCount = mLastCount = mPluggedCount = mUnpluggedCount = 0;
+            mLoadedCount = mPluggedCount = mUnpluggedCount = 0;
             if (detachIfReset) {
                 detach();
             }
@@ -993,7 +1003,6 @@
         void readSummaryFromParcelLocked(Parcel in) {
             mLoadedCount = in.readLong();
             mCount = mLoadedCount;
-            mLastCount = 0;
             mUnpluggedCount = mPluggedCount = mLoadedCount;
         }
     }
@@ -7566,6 +7575,8 @@
         mFlashlightOnTimer = new StopwatchTimer(mClocks, null, -9, null, mOnBatteryTimeBase);
         mCameraOnTimer = new StopwatchTimer(mClocks, null, -13, null, mOnBatteryTimeBase);
         mBluetoothScanTimer = new StopwatchTimer(mClocks, null, -14, null, mOnBatteryTimeBase);
+        mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryScreenOffTimeBase);
+        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase);
         mOnBattery = mOnBatteryInternal = false;
         long uptime = mClocks.uptimeMillis() * 1000;
         long realtime = mClocks.elapsedRealtime() * 1000;
@@ -8123,6 +8134,8 @@
         mDischargeAmountScreenOffSinceCharge = 0;
         mDischargeStepTracker.init();
         mChargeStepTracker.init();
+        mDischargeScreenOffCounter.reset(false);
+        mDischargeCounter.reset(false);
     }
 
     public void resetAllStatsCmdLocked() {
@@ -9327,6 +9340,7 @@
             mHistoryCur.states2 |= HistoryItem.STATE2_CHARGING_FLAG;
             mHistoryCur.batteryStatus = (byte)status;
             mHistoryCur.batteryLevel = (byte)level;
+            mHistoryCur.batteryChargeUAh = chargeUAh;
             mMaxChargeStepLevel = mMinDischargeStepLevel =
                     mLastChargeStepLevel = mLastDischargeStepLevel = level;
             mLastChargingStateLevel = level;
@@ -9358,6 +9372,12 @@
             mHistoryCur.batteryPlugType = (byte)plugType;
             mHistoryCur.batteryTemperature = (short)temp;
             mHistoryCur.batteryVoltage = (char)volt;
+            if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+                // Only record discharges
+                final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+                mDischargeCounter.addCountLocked(chargeDiff);
+                mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+            }
             mHistoryCur.batteryChargeUAh = chargeUAh;
             setOnBatteryLocked(elapsedRealtime, uptime, onBattery, oldStatus, level);
         } else {
@@ -9394,6 +9414,12 @@
             }
             if (chargeUAh >= (mHistoryCur.batteryChargeUAh+10)
                     || chargeUAh <= (mHistoryCur.batteryChargeUAh-10)) {
+                if (chargeUAh < mHistoryCur.batteryChargeUAh) {
+                    // Only record discharges
+                    final long chargeDiff = mHistoryCur.batteryChargeUAh - chargeUAh;
+                    mDischargeCounter.addCountLocked(chargeDiff);
+                    mDischargeScreenOffCounter.addCountLocked(chargeDiff);
+                }
                 mHistoryCur.batteryChargeUAh = chargeUAh;
                 changed = true;
             }
@@ -10075,6 +10101,8 @@
         mChargeStepTracker.readFromParcel(in);
         mDailyDischargeStepTracker.readFromParcel(in);
         mDailyChargeStepTracker.readFromParcel(in);
+        mDischargeCounter.readSummaryFromParcelLocked(in);
+        mDischargeScreenOffCounter.readSummaryFromParcelLocked(in);
         int NPKG = in.readInt();
         if (NPKG > 0) {
             mDailyPackageChanges = new ArrayList<>(NPKG);
@@ -10425,6 +10453,8 @@
         mChargeStepTracker.writeToParcel(out);
         mDailyDischargeStepTracker.writeToParcel(out);
         mDailyChargeStepTracker.writeToParcel(out);
+        mDischargeCounter.writeSummaryFromParcelLocked(out);
+        mDischargeScreenOffCounter.writeSummaryFromParcelLocked(out);
         if (mDailyPackageChanges != null) {
             final int NPKG = mDailyPackageChanges.size();
             out.writeInt(NPKG);
@@ -10880,6 +10910,8 @@
         mDischargeAmountScreenOffSinceCharge = in.readInt();
         mDischargeStepTracker.readFromParcel(in);
         mChargeStepTracker.readFromParcel(in);
+        mDischargeCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
+        mDischargeScreenOffCounter = new LongSamplingCounter(mOnBatteryTimeBase, in);
         mLastWriteTime = in.readLong();
 
         mKernelWakelockStats.clear();
@@ -11028,6 +11060,8 @@
         out.writeInt(mDischargeAmountScreenOffSinceCharge);
         mDischargeStepTracker.writeToParcel(out);
         mChargeStepTracker.writeToParcel(out);
+        mDischargeCounter.writeToParcel(out);
+        mDischargeScreenOffCounter.writeToParcel(out);
         out.writeLong(mLastWriteTime);
 
         if (inclUids) {
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 1099ef7..366fc1a 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1586,7 +1586,13 @@
     private ActionMode createStandaloneActionMode(ActionMode.Callback callback) {
         endOnGoingFadeAnimation();
         cleanupPrimaryActionMode();
-        if (mPrimaryActionModeView == null) {
+        // We want to create new mPrimaryActionModeView in two cases: if there is no existing
+        // instance at all, or if there is one, but it is detached from window. The latter case
+        // might happen when app is resized in multi-window mode and decor view is preserved
+        // along with the main app window. Keeping mPrimaryActionModeView reference doesn't cause
+        // app memory leaks because killMode() is called when the dismiss animation ends and from
+        // cleanupPrimaryActionMode() invocation above.
+        if (mPrimaryActionModeView == null || !mPrimaryActionModeView.isAttachedToWindow()) {
             if (mWindow.isFloating()) {
                 // Use the action bar theme.
                 final TypedValue outValue = new TypedValue();
@@ -1652,6 +1658,7 @@
                 ViewStub stub = (ViewStub) findViewById(R.id.action_mode_bar_stub);
                 if (stub != null) {
                     mPrimaryActionModeView = (ActionBarContextView) stub.inflate();
+                    mPrimaryActionModePopup = null;
                 }
             }
         }
@@ -2316,9 +2323,14 @@
                 }
                 if (mPrimaryActionModeView != null) {
                     endOnGoingFadeAnimation();
+                    // Store action mode view reference, so we can access it safely when animation
+                    // ends. mPrimaryActionModePopup is set together with mPrimaryActionModeView,
+                    // so no need to store reference to it in separate variable.
+                    final ActionBarContextView lastActionModeView = mPrimaryActionModeView;
                     mFadeAnim = ObjectAnimator.ofFloat(mPrimaryActionModeView, View.ALPHA,
                             1f, 0f);
                     mFadeAnim.addListener(new Animator.AnimatorListener() {
+
                                 @Override
                                 public void onAnimationStart(Animator animation) {
 
@@ -2326,12 +2338,17 @@
 
                                 @Override
                                 public void onAnimationEnd(Animator animation) {
-                                    mPrimaryActionModeView.setVisibility(GONE);
-                                    if (mPrimaryActionModePopup != null) {
-                                        mPrimaryActionModePopup.dismiss();
+                                    // If mPrimaryActionModeView has changed - it means that we've
+                                    // cleared the content while preserving decor view. We don't
+                                    // want to change the state of new instances accidentally here.
+                                    if (lastActionModeView == mPrimaryActionModeView) {
+                                        lastActionModeView.setVisibility(GONE);
+                                        if (mPrimaryActionModePopup != null) {
+                                            mPrimaryActionModePopup.dismiss();
+                                        }
+                                        lastActionModeView.killMode();
+                                        mFadeAnim = null;
                                     }
-                                    mPrimaryActionModeView.removeAllViews();
-                                    mFadeAnim = null;
                                 }
 
                                 @Override
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index 18408aa..9ad750d 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -528,16 +528,22 @@
 
     @Override
     public void setTitle(CharSequence title) {
+        setTitle(title, true);
+    }
+
+    public void setTitle(CharSequence title, boolean updateAccessibilityTitle) {
         if (mTitleView != null) {
             mTitleView.setText(title);
         } else if (mDecorContentParent != null) {
             mDecorContentParent.setWindowTitle(title);
         }
         mTitle = title;
-        WindowManager.LayoutParams params = getAttributes();
-        if (!TextUtils.equals(title, params.accessibilityTitle)) {
-            params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
-            dispatchWindowAttributesChanged(getAttributes());
+        if (updateAccessibilityTitle) {
+            WindowManager.LayoutParams params = getAttributes();
+            if (!TextUtils.equals(title, params.accessibilityTitle)) {
+                params.accessibilityTitle = TextUtils.stringOrSpannedString(title);
+                dispatchWindowAttributesChanged(getAttributes());
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java
index 59b4b35..fc189a3 100644
--- a/core/java/com/android/internal/view/IInputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java
@@ -33,6 +33,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionInspector;
 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
+import android.view.inputmethod.InputContentInfo;
 
 public abstract class IInputConnectionWrapper extends IInputContext.Stub {
     static final String TAG = "IInputConnectionWrapper";
@@ -61,6 +62,7 @@
     private static final int DO_CLEAR_META_KEY_STATES = 130;
     private static final int DO_REQUEST_UPDATE_CURSOR_ANCHOR_INFO = 140;
     private static final int DO_CLOSE_CONNECTION = 150;
+    private static final int DO_INSERT_CONTENT = 160;
 
     @GuardedBy("mLock")
     @Nullable
@@ -241,6 +243,11 @@
         dispatchMessage(obtainMessage(DO_CLOSE_CONNECTION));
     }
 
+    public void insertContent(InputContentInfo inputContentInfo, Bundle opts,
+            int seq, IInputContextCallback callback) {
+        dispatchMessage(obtainMessageOOSC(DO_INSERT_CONTENT, inputContentInfo, opts, seq, callback));
+    }
+
     void dispatchMessage(Message msg) {
         // If we are calling this from the main thread, then we can call
         // right through.  Otherwise, we need to send the message to the
@@ -552,6 +559,29 @@
                 }
                 return;
             }
+            case DO_INSERT_CONTENT: {
+                SomeArgs args = (SomeArgs) msg.obj;
+                try {
+                    InputConnection ic = getInputConnection();
+                    if (ic == null || !isActive()) {
+                        Log.w(TAG, "insertContent on inactive InputConnection");
+                        args.callback.setInsertContentResult(false, args.seq);
+                        return;
+                    }
+                    final InputContentInfo inputContentInfo = (InputContentInfo) args.arg1;
+                    if (inputContentInfo == null || !inputContentInfo.validate()) {
+                        Log.w(TAG, "insertContent with invalid inputContentInfo="
+                                + inputContentInfo);
+                        args.callback.setInsertContentResult(false, args.seq);
+                        return;
+                    }
+                    args.callback.setInsertContentResult(
+                            ic.insertContent(inputContentInfo, (Bundle) args.arg2), args.seq);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Got RemoteException calling insertContent", e);
+                }
+                return;
+            }
         }
         Log.w(TAG, "Unhandled message code: " + msg.what);
     }
@@ -582,9 +612,11 @@
         return mH.obtainMessage(what, arg1, arg2, args);
     }
 
-    Message obtainMessageOSC(int what, Object arg1, int seq, IInputContextCallback callback) {
+    Message obtainMessageOOSC(int what, Object arg1, Object arg2, int seq,
+            IInputContextCallback callback) {
         SomeArgs args = new SomeArgs();
         args.arg1 = arg1;
+        args.arg2 = arg2;
         args.callback = callback;
         args.seq = seq;
         return mH.obtainMessage(what, 0, 0, args);
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index f7ec420..bd47355 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -21,6 +21,7 @@
 import android.view.inputmethod.CompletionInfo;
 import android.view.inputmethod.CorrectionInfo;
 import android.view.inputmethod.ExtractedTextRequest;
+import android.view.inputmethod.InputContentInfo;
 
 import com.android.internal.view.IInputContextCallback;
 
@@ -74,6 +75,9 @@
 
     void getSelectedText(int flags, int seq, IInputContextCallback callback);
 
-    void requestUpdateCursorAnchorInfo(in int cursorUpdateMode, int seq,
+    void requestUpdateCursorAnchorInfo(int cursorUpdateMode, int seq,
+            IInputContextCallback callback);
+
+    void insertContent(in InputContentInfo inputContentInfo, in Bundle opts, int sec,
             IInputContextCallback callback);
 }
diff --git a/core/java/com/android/internal/view/IInputContextCallback.aidl b/core/java/com/android/internal/view/IInputContextCallback.aidl
index 54ea306..933cdc0 100644
--- a/core/java/com/android/internal/view/IInputContextCallback.aidl
+++ b/core/java/com/android/internal/view/IInputContextCallback.aidl
@@ -28,4 +28,5 @@
     void setExtractedText(in ExtractedText extractedText, int seq);
     void setSelectedText(CharSequence selectedText, int seq);
     void setRequestUpdateCursorAnchorInfoResult(boolean result, int seq);
+    void setInsertContentResult(boolean result, int seq);
 }
diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java
index f9884d8..6d4d45c 100644
--- a/core/java/com/android/internal/view/InputConnectionWrapper.java
+++ b/core/java/com/android/internal/view/InputConnectionWrapper.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.view;
 
+import android.content.ClipData;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.RemoteException;
@@ -29,6 +30,7 @@
 import android.view.inputmethod.InputConnection;
 import android.view.inputmethod.InputConnectionInspector;
 import android.view.inputmethod.InputConnectionInspector.MissingMethodFlags;
+import android.view.inputmethod.InputContentInfo;
 
 public class InputConnectionWrapper implements InputConnection {
     private static final int MAX_WAIT_TIME_MILLIS = 2000;
@@ -46,7 +48,8 @@
         public ExtractedText mExtractedText;
         public int mCursorCapsMode;
         public boolean mRequestUpdateCursorAnchorInfoResult;
-        
+        public boolean mInsertContentResult;
+
         // A 'pool' of one InputContextCallback.  Each ICW request will attempt to gain
         // exclusive access to this object.
         private static InputContextCallback sInstance = new InputContextCallback();
@@ -172,6 +175,19 @@
             }
         }
 
+        public void setInsertContentResult(boolean result, int seq) {
+            synchronized (this) {
+                if (seq == mSeq) {
+                    mInsertContentResult = result;
+                    mHaveValue = true;
+                    notifyAll();
+                } else {
+                    Log.i(TAG, "Got out-of-sequence callback " + seq + " (expected " + mSeq
+                            + ") in setInsertContentResult, ignoring.");
+                }
+            }
+        }
+
         /**
          * Waits for a result for up to {@link #MAX_WAIT_TIME_MILLIS} milliseconds.
          * 
@@ -491,6 +507,28 @@
         // Nothing should happen when called from input method.
     }
 
+    public boolean insertContent(InputContentInfo inputContentInfo, Bundle opts) {
+        boolean result = false;
+        if (isMethodMissing(MissingMethodFlags.INSERT_CONTENT)) {
+            // This method is not implemented.
+            return false;
+        }
+        try {
+            InputContextCallback callback = InputContextCallback.getInstance();
+            mIInputContext.insertContent(inputContentInfo, opts, callback.mSeq, callback);
+            synchronized (callback) {
+                callback.waitForResultLocked();
+                if (callback.mHaveValue) {
+                    result = callback.mInsertContentResult;
+                }
+            }
+            callback.dispose();
+        } catch (RemoteException e) {
+            return false;
+        }
+        return result;
+    }
+
     private boolean isMethodMissing(@MissingMethodFlags final int methodFlag) {
         return (mMissingMethods & methodFlag) == methodFlag;
     }
diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
index 9e2cbdb..d28ab07 100644
--- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
+++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java
@@ -30,6 +30,8 @@
 @HasNativeInterpolator
 public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeInterpolator {
 
+    // If the duration of an animation is more than 300 frames, we cap the sample size to 300.
+    private static final int MAX_SAMPLE_POINTS = 300;
     private TimeInterpolator mSourceInterpolator;
     private final float mLut[];
 
@@ -47,6 +49,7 @@
         int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
         // We need 2 frame values as the minimal.
         int numAnimFrames = Math.max(2, (int) Math.ceil(((double) duration) / animIntervalMs));
+        numAnimFrames = Math.min(numAnimFrames, MAX_SAMPLE_POINTS);
         float values[] = new float[numAnimFrames];
         float lastFrame = numAnimFrames - 1;
         for (int i = 0; i < numAnimFrames; i++) {
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index dc7b7f5..d2a43b7 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -48,6 +48,11 @@
 
     private int mIndentLines;
 
+    /**
+     * Id of the child that's also visible in the contracted layout.
+     */
+    private int mContractedChildId;
+
     public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
@@ -255,14 +260,29 @@
         return copy;
     }
 
-    @RemotableViewMethod
     /**
      * Sets how many lines should be indented to avoid a floating image.
      */
+    @RemotableViewMethod
     public void setNumIndentLines(int numberLines) {
         mIndentLines = numberLines;
     }
 
+    /**
+     * Set id of the child that's also visible in the contracted layout.
+     */
+    @RemotableViewMethod
+    public void setContractedChildId(int contractedChildId) {
+        mContractedChildId = contractedChildId;
+    }
+
+    /**
+     * Get id of the child that's also visible in the contracted layout.
+     */
+    public int getContractedChildId() {
+        return mContractedChildId;
+    }
+
     public static class LayoutParams extends MarginLayoutParams {
 
         boolean hide = false;
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 4b2a72d..47252ad 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -95,6 +95,12 @@
     return reinterpret_cast<jlong>(animatorSet);
 }
 
+static void setVectorDrawableTarget(JNIEnv*, jobject,jlong animatorPtr, jlong vectorDrawablePtr) {
+    VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(vectorDrawablePtr);
+    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
+    set->setVectorDrawable(tree);
+}
+
 static jlong createGroupPropertyHolder(JNIEnv*, jobject, jlong nativePtr, jint propertyId,
         jfloat startValue, jfloat endValue) {
     VectorDrawable::Group* group = reinterpret_cast<VectorDrawable::Group*>(nativePtr);
@@ -136,14 +142,24 @@
             startValue, endValue);
     return reinterpret_cast<jlong>(newHolder);
 }
-static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
+static void setFloatPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
         jfloatArray srcData, jint length) {
-
     jfloat* propertyData = env->GetFloatArrayElements(srcData, nullptr);
-    PropertyValuesHolder* holder = reinterpret_cast<PropertyValuesHolder*>(propertyHolderPtr);
+    PropertyValuesHolderImpl<float>* holder =
+            reinterpret_cast<PropertyValuesHolderImpl<float>*>(propertyHolderPtr);
     holder->setPropertyDataSource(propertyData, length);
     env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
 }
+
+static void setIntPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
+        jintArray srcData, jint length) {
+    jint* propertyData = env->GetIntArrayElements(srcData, nullptr);
+    PropertyValuesHolderImpl<int>* holder =
+            reinterpret_cast<PropertyValuesHolderImpl<int>*>(propertyHolderPtr);
+    holder->setPropertyDataSource(propertyData, length);
+    env->ReleaseIntArrayElements(srcData, propertyData, JNI_ABORT);
+}
+
 static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
     PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
     AnimationListener* listener = createAnimationListener(env, finishListener, id);
@@ -168,13 +184,15 @@
 
 static const JNINativeMethod gMethods[] = {
     {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet},
+    {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget},
     {"nAddAnimator", "(JJJJJI)V", (void*)addAnimator},
     {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder},
     {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder},
     {"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder},
     {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
     {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
-    {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
+    {"nSetPropertyHolderData", "(J[FI)V", (void*)setFloatPropertyHolderData},
+    {"nSetPropertyHolderData", "(J[II)V", (void*)setIntPropertyHolderData},
     {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
     {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
     {"nEnd", "!(J)V", (void*)end},
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 5b4bfe9..212bf57 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -32,6 +32,7 @@
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
+#include <utils/Timers.h>
 #include <android_runtime/android_view_Surface.h>
 #include <system/window.h>
 
@@ -44,6 +45,7 @@
 #include <FrameMetricsObserver.h>
 #include <IContextFactory.h>
 #include <JankTracker.h>
+#include <PropertyValuesAnimatorSet.h>
 #include <RenderNode.h>
 #include <renderthread/CanvasContext.h>
 #include <renderthread/RenderProxy.h>
@@ -122,6 +124,31 @@
     std::vector<OnFinishedEvent> mOnFinishedEvents;
 };
 
+class FinishAndInvokeListener : public MessageHandler {
+public:
+    explicit FinishAndInvokeListener(PropertyValuesAnimatorSet* anim)
+            : mAnimator(anim) {
+        mListener = anim->getOneShotListener();
+        mRequestId = anim->getRequestId();
+    }
+
+    virtual void handleMessage(const Message& message) {
+        if (mAnimator->getRequestId() == mRequestId) {
+            // Request Id has not changed, meaning there's no animation lifecyle change since the
+            // message is posted, so go ahead and call finish to make sure the PlayState is properly
+            // updated. This is needed because before the next frame comes in from UI thread to
+            // trigger an animation update, there could be reverse/cancel etc. So we need to update
+            // the playstate in time to ensure all the subsequent events get chained properly.
+            mAnimator->end();
+        }
+        mListener->onAnimationFinished(nullptr);
+    }
+private:
+    sp<PropertyValuesAnimatorSet> mAnimator;
+    sp<AnimationListener> mListener;
+    uint32_t mRequestId;
+};
+
 class RenderingException : public MessageHandler {
 public:
     RenderingException(JavaVM* vm, const std::string& message)
@@ -160,6 +187,15 @@
 
     virtual void prepareTree(TreeInfo& info) override {
         info.errorHandler = this;
+
+        for (auto& anim : mVectorDrawableAnimators) {
+            // Assume that the property change in VD from the animators will not be consumed. Mark
+            // otherwise if the VDs are found in the display list tree. For VDs that are not in
+            // the display list tree, we stop providing animation pulses by 1) removing them from
+            // the animation list, 2) post a delayed message to end them at end time so their
+            // listeners can receive the corresponding callbacks.
+            anim->getVectorDrawable()->setPropertyChangeWillBeConsumed(false);
+        }
         // TODO: This is hacky
         info.windowInsetLeft = -stagingProperties().getLeft();
         info.windowInsetTop = -stagingProperties().getTop();
@@ -169,16 +205,46 @@
         info.windowInsetLeft = 0;
         info.windowInsetTop = 0;
         info.errorHandler = nullptr;
+
+        for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) {
+            if (!(*it)->getVectorDrawable()->getPropertyChangeWillBeConsumed()) {
+                // Vector Drawable is not in the display list, we should remove this animator from
+                // the list and post a delayed message to end the animator.
+                detachVectorDrawableAnimator(it->get());
+                it = mVectorDrawableAnimators.erase(it);
+            } else {
+                ++it;
+            }
+        }
+        info.out.hasAnimations |= !mVectorDrawableAnimators.empty();
     }
 
     void sendMessage(const sp<MessageHandler>& handler) {
         mLooper->sendMessage(handler, 0);
     }
 
+    void sendMessageDelayed(const sp<MessageHandler>& handler, nsecs_t delayInMs) {
+        mLooper->sendMessageDelayed(ms2ns(delayInMs), handler, 0);
+    }
+
     void attachAnimatingNode(RenderNode* animatingNode) {
         mPendingAnimatingRenderNodes.push_back(animatingNode);
     }
 
+    void attachPendingVectorDrawableAnimators() {
+        mVectorDrawableAnimators.insert(mPendingVectorDrawableAnimators.begin(),
+                mPendingVectorDrawableAnimators.end());
+        mPendingVectorDrawableAnimators.clear();
+    }
+
+    void detachAnimators() {
+        // Remove animators from the list and post a delayed message in future to end the animator
+        for (auto& anim : mVectorDrawableAnimators) {
+            detachVectorDrawableAnimator(anim.get());
+        }
+        mVectorDrawableAnimators.clear();
+    }
+
     void doAttachAnimatingNodes(AnimationContext* context) {
         for (size_t i = 0; i < mPendingAnimatingRenderNodes.size(); i++) {
             RenderNode* node = mPendingAnimatingRenderNodes[i].get();
@@ -187,17 +253,57 @@
         mPendingAnimatingRenderNodes.clear();
     }
 
+    void runVectorDrawableAnimators(AnimationContext* context) {
+        for (auto it = mVectorDrawableAnimators.begin(); it != mVectorDrawableAnimators.end();) {
+            (*it)->pushStaging(*context);
+            if ((*it)->animate(*context)) {
+                it = mVectorDrawableAnimators.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
     void destroy() {
         for (auto& renderNode : mPendingAnimatingRenderNodes) {
             renderNode->animators().endAllStagingAnimators();
         }
         mPendingAnimatingRenderNodes.clear();
+        mPendingVectorDrawableAnimators.clear();
+    }
+
+    void addVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
+        mPendingVectorDrawableAnimators.insert(anim);
     }
 
 private:
     sp<Looper> mLooper;
     JavaVM* mVm;
     std::vector< sp<RenderNode> > mPendingAnimatingRenderNodes;
+    std::set< sp<PropertyValuesAnimatorSet> > mPendingVectorDrawableAnimators;
+    std::set< sp<PropertyValuesAnimatorSet> > mVectorDrawableAnimators;
+    void detachVectorDrawableAnimator(PropertyValuesAnimatorSet* anim) {
+        if (anim->isInfinite() || !anim->isRunning()) {
+            // Do not need to post anything if the animation is infinite (i.e. no meaningful
+            // end listener action), or if the animation has already ended.
+            return;
+        }
+        nsecs_t remainingTimeInMs = anim->getRemainingPlayTime();
+        // Post a delayed onFinished event that is scheduled to be handled when the animator ends.
+        if (anim->getOneShotListener()) {
+            // VectorDrawable's oneshot listener is updated when there are user triggered animation
+            // lifecycle changes, such as start(), end(), etc. By using checking and clearing
+            // one shot listener, we ensure the same end listener event gets posted only once.
+            // Therefore no duplicates. Another benefit of using one shot listener is that no
+            // removal is necessary: the end time of animation will not change unless triggered by
+            // user events, in which case the already posted listener's id will become stale, and
+            // the onFinished callback will then be ignored.
+            sp<FinishAndInvokeListener> message
+                    = new FinishAndInvokeListener(anim);
+            sendMessageDelayed(message, remainingTimeInMs);
+            anim->clearOneShotListener();
+        }
+    }
 };
 
 class AnimationContextBridge : public AnimationContext {
@@ -213,8 +319,16 @@
     virtual void startFrame(TreeInfo::TraversalMode mode) {
         if (mode == TreeInfo::MODE_FULL) {
             mRootNode->doAttachAnimatingNodes(this);
+            mRootNode->attachPendingVectorDrawableAnimators();
         }
         AnimationContext::startFrame(mode);
+        // Run VectorDrawable animators in the beginning of the frame instead of during prepareTree,
+        // because one VD can be in multiple render nodes' display list. So it's more simple to
+        // run them all at once before prepareTree than running them or checking whether they have
+        // already ran in each RenderNode. Note that these animators don't damage the RenderNodes.
+        // The damaging is done in prepareTree as needed after checking whether a VD has been
+        // modified.
+        mRootNode->runVectorDrawableAnimators(this);
     }
 
     // Runs any animations still left in mCurrentFrameAnimations
@@ -223,6 +337,10 @@
         postOnFinishedEvents();
     }
 
+    virtual void detachAnimators() override {
+        mRootNode->detachAnimators();
+    }
+
     virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener) {
         OnFinishedEvent event(animator, listener);
         mOnFinishedEvents.push_back(event);
@@ -230,6 +348,7 @@
 
     virtual void destroy() {
         AnimationContext::destroy();
+        detachAnimators();
         postOnFinishedEvents();
     }
 
@@ -528,6 +647,13 @@
     rootRenderNode->attachAnimatingNode(animatingNode);
 }
 
+static void android_view_ThreadedRenderer_registerVectorDrawableAnimator(JNIEnv* env, jobject clazz,
+        jlong rootNodePtr, jlong animatorPtr) {
+    RootRenderNode* rootRenderNode = reinterpret_cast<RootRenderNode*>(rootNodePtr);
+    PropertyValuesAnimatorSet* animator = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorPtr);
+    rootRenderNode->addVectorDrawableAnimator(animator);
+}
+
 static void android_view_ThreadedRenderer_invokeFunctor(JNIEnv* env, jobject clazz,
         jlong functorPtr, jboolean waitForCompletion) {
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
@@ -739,6 +865,7 @@
     { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
+    { "nRegisterVectorDrawableAnimator", "(JJ)V", (void*) android_view_ThreadedRenderer_registerVectorDrawableAnimator },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 89abeff..89036dd 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -360,6 +360,7 @@
     <!-- Added in N -->
     <protected-broadcast android:name="android.intent.action.ANR" />
     <protected-broadcast android:name="android.intent.action.CALL" />
+    <protected-broadcast android:name="android.intent.action.CALL_PRIVILEGED" />
     <protected-broadcast android:name="android.intent.action.DROPBOX_ENTRY_ADDED" />
     <protected-broadcast android:name="android.intent.action.INPUT_METHOD_CHANGED" />
     <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
@@ -471,6 +472,7 @@
     <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
     <protected-broadcast android:name="com.android.ims.IMS_INCOMING_CALL" />
     <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_UP" />
+    <protected-broadcast android:name="com.android.ims.internal.uce.UCE_SERVICE_DOWN" />
     <protected-broadcast android:name="com.android.intent.action.IMS_FEATURE_CHANGED" />
     <protected-broadcast android:name="com.android.intent.action.IMS_CONFIG_CHANGED" />
 
@@ -480,6 +482,7 @@
 
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+    <protected-broadcast android:name="com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK" />
 
     <protected-broadcast android:name="com.android.server.am.ACTION_RESET_DEMO" />
 
@@ -1623,6 +1626,14 @@
     <permission android:name="android.permission.MANAGE_USERS"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @hide Allows an application to create, remove users and get the list of
+         users on the device. Applications holding this permission can only create restricted,
+         guest, managed, and ephemeral users. For creating other kind of users,
+         {@link android.Manifest.permission#MANAGE_USERS} is needed.
+         This permission is not available to third party applications. -->
+    <permission android:name="android.permission.CREATE_USERS"
+        android:protectionLevel="signature" />
+
     <!-- @hide Allows an application to set the profile owners and the device owner.
          This permission is not available to third party applications.-->
     <permission android:name="android.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS"
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/drawable-watch/dialog_background_material.xml
similarity index 76%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/drawable-watch/dialog_background_material.xml
index 8dbc905..de52f08 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/drawable-watch/dialog_background_material.xml
@@ -13,8 +13,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
-</resources>
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
+    <solid android:color="?attr/colorBackground" />
+</shape>
diff --git a/core/res/res/layout-notround/alert_dialog_header_micro.xml b/core/res/res/layout-notround-watch/alert_dialog_header_micro.xml
similarity index 100%
rename from core/res/res/layout-notround/alert_dialog_header_micro.xml
rename to core/res/res/layout-notround-watch/alert_dialog_header_micro.xml
diff --git a/core/res/res/layout-round/alert_dialog_header_micro.xml b/core/res/res/layout-round-watch/alert_dialog_header_micro.xml
similarity index 100%
rename from core/res/res/layout-round/alert_dialog_header_micro.xml
rename to core/res/res/layout-round-watch/alert_dialog_header_micro.xml
diff --git a/core/res/res/layout/alert_dialog_micro.xml b/core/res/res/layout-watch/alert_dialog_material.xml
similarity index 83%
rename from core/res/res/layout/alert_dialog_micro.xml
rename to core/res/res/layout-watch/alert_dialog_material.xml
index 04f8a2a..e627d42 100644
--- a/core/res/res/layout/alert_dialog_micro.xml
+++ b/core/res/res/layout-watch/alert_dialog_material.xml
@@ -29,8 +29,8 @@
                 android:layout_height="wrap_content">
             <!-- Top Panel -->
             <FrameLayout
-                    android:paddingLeft="@dimen/dialog_padding_micro"
-                    android:paddingRight="@dimen/dialog_padding_micro"
+                    android:paddingLeft="?dialogPreferredPadding"
+                    android:paddingRight="?dialogPreferredPadding"
                     android:layout_width="match_parent"
                     android:layout_height="wrap_content"
                     android:id="@+id/topPanel">
@@ -48,9 +48,9 @@
                 <TextView android:id="@+id/message"
                         android:layout_width="match_parent"
                         android:layout_height="wrap_content"
-                        android:textAppearance="@style/TextAppearance.Micro.AlertDialog.Message"
-                        android:paddingStart="@dimen/dialog_padding_micro"
-                        android:paddingEnd="@dimen/dialog_padding_micro"
+                        android:textAppearance="@style/TextAppearance.Material.Body1"
+                        android:paddingStart="?dialogPreferredPadding"
+                        android:paddingEnd="?dialogPreferredPadding"
                         android:paddingTop="8dip"
                         android:paddingBottom="8dip"/>
             </FrameLayout>
@@ -78,31 +78,31 @@
                         android:dividerPadding="0dip"
                         android:orientation="vertical"
                         android:minHeight="@dimen/alert_dialog_button_bar_height"
-                        android:paddingBottom="@dimen/dialog_padding_micro"
+                        android:paddingBottom="?dialogPreferredPadding"
                         style="?android:attr/buttonBarStyle"
                         android:layoutDirection="locale"
                         android:measureWithLargestChild="true">
                     <Button android:id="@+id/button1"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="@dimen/dialog_padding_micro"
-                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            android:layout_marginLeft="?dialogPreferredPadding"
+                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
                     <Button android:id="@+id/button3"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="@dimen/dialog_padding_micro"
-                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            android:layout_marginLeft="?dialogPreferredPadding"
+                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
                     <Button android:id="@+id/button2"
                             android:layout_gravity="start"
                             android:layout_weight="1"
-                            android:layout_marginLeft="@dimen/dialog_padding_micro"
-                            android:layout_marginRight="@dimen/dialog_padding_micro"
+                            android:layout_marginLeft="?dialogPreferredPadding"
+                            android:layout_marginRight="?dialogPreferredPadding"
                             style="?android:attr/buttonBarButtonStyle"
                             android:layout_width="match_parent"
                             android:layout_height="wrap_content" />
diff --git a/core/res/res/layout-watch/input_method_extract_view.xml b/core/res/res/layout-watch/input_method_extract_view.xml
index de4ca69..038b766 100644
--- a/core/res/res/layout-watch/input_method_extract_view.xml
+++ b/core/res/res/layout-watch/input_method_extract_view.xml
@@ -31,7 +31,8 @@
         android:inputType="text"
         android:layout_weight="1"
         android:fontFamily="sans-serif-condensed-light"
-        android:textColor="@color/primary_text_default_material_dark"
+        android:textColor="@color/primary_text_material_dark"
+        android:textColorHint="@color/secondary_text_material_dark"
         android:textColorHighlight="@color/accent_material_dark"
         android:textSize="18dp"
         android:gravity="bottom|right"
diff --git a/core/res/res/layout/number_picker_with_selector_wheel_micro.xml b/core/res/res/layout-watch/number_picker_material.xml
similarity index 100%
rename from core/res/res/layout/number_picker_with_selector_wheel_micro.xml
rename to core/res/res/layout-watch/number_picker_material.xml
diff --git a/core/res/res/layout/preference_micro.xml b/core/res/res/layout-watch/preference_material.xml
similarity index 100%
rename from core/res/res/layout/preference_micro.xml
rename to core/res/res/layout-watch/preference_material.xml
diff --git a/core/res/res/layout/notification_material_action_list.xml b/core/res/res/layout/notification_material_action_list.xml
index 4670dca..caeb43a 100644
--- a/core/res/res/layout/notification_material_action_list.xml
+++ b/core/res/res/layout/notification_material_action_list.xml
@@ -17,7 +17,8 @@
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/actions_container"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content">
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom">
     <com.android.internal.widget.NotificationActionListLayout
             android:id="@+id/actions"
             android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_template_material_big_base.xml b/core/res/res/layout/notification_template_material_big_base.xml
index c54fa18..8b0b476 100644
--- a/core/res/res/layout/notification_template_material_big_base.xml
+++ b/core/res/res/layout/notification_template_material_big_base.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<LinearLayout
+<FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
@@ -22,43 +22,49 @@
     android:orientation="vertical"
     android:tag="big"
     >
-    <FrameLayout
-        android:id="@+id/status_bar_latest_event_content"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:tag="base"
-        >
-        <include layout="@layout/notification_template_header" />
-        <LinearLayout
-            android:id="@+id/notification_main_column"
+    <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="top"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:layout_marginEnd="@dimen/notification_content_margin_end"
-            android:layout_marginTop="@dimen/notification_content_margin_top"
-            android:layout_marginBottom="@dimen/notification_content_margin_bottom"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="@dimen/notification_action_list_height"
             android:orientation="vertical"
             >
-            <include layout="@layout/notification_template_part_line1" />
-            <include layout="@layout/notification_template_text" />
-        </LinearLayout>
         <FrameLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:layout_gravity="bottom"
-            android:layout_marginStart="@dimen/notification_content_margin_start"
-            android:layout_marginBottom="15dp"
-            android:layout_marginEnd="@dimen/notification_content_margin_end">
-            <include layout="@layout/notification_template_progress" />
+            android:layout_gravity="top"
+            >
+            <include layout="@layout/notification_template_header" />
+            <LinearLayout
+                android:id="@+id/notification_main_column"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="top"
+                android:layout_marginStart="@dimen/notification_content_margin_start"
+                android:layout_marginEnd="@dimen/notification_content_margin_end"
+                android:layout_marginTop="@dimen/notification_content_margin_top"
+                android:layout_marginBottom="@dimen/notification_content_margin_bottom"
+                android:orientation="vertical"
+                >
+                <include layout="@layout/notification_template_part_line1" />
+                <include layout="@layout/notification_template_text" />
+            </LinearLayout>
+            <FrameLayout
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:layout_gravity="bottom"
+                android:layout_marginStart="@dimen/notification_content_margin_start"
+                android:layout_marginBottom="15dp"
+                android:layout_marginEnd="@dimen/notification_content_margin_end">
+                <include layout="@layout/notification_template_progress" />
+            </FrameLayout>
+            <include layout="@layout/notification_template_right_icon" />
         </FrameLayout>
-        <include layout="@layout/notification_template_right_icon" />
-    </FrameLayout>
-    <ViewStub android:layout="@layout/notification_material_reply_text"
-            android:id="@+id/notification_material_reply_container"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-    />
+        <ViewStub android:layout="@layout/notification_material_reply_text"
+                android:id="@+id/notification_material_reply_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+        />
+    </LinearLayout>
     <include layout="@layout/notification_material_action_list" />
-</LinearLayout>
+</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_picture.xml b/core/res/res/layout/notification_template_material_big_picture.xml
index d87b9d9..83c0fec 100644
--- a/core/res/res/layout/notification_template_material_big_picture.xml
+++ b/core/res/res/layout/notification_template_material_big_picture.xml
@@ -30,6 +30,7 @@
             android:layout_marginTop="@dimen/notification_content_margin_top"
             android:clipToPadding="false"
             android:orientation="vertical"
+            android:id="@+id/notification_action_list_margin_target"
             >
         <LinearLayout
             android:id="@+id/notification_main_column"
@@ -60,6 +61,6 @@
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 />
-        <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
+    <include layout="@layout/notification_material_action_list" />
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_big_text.xml b/core/res/res/layout/notification_template_material_big_text.xml
index 71600ef..f4f783e 100644
--- a/core/res/res/layout/notification_template_material_big_text.xml
+++ b/core/res/res/layout/notification_template_material_big_text.xml
@@ -24,10 +24,12 @@
     <include layout="@layout/notification_template_header" />
 
     <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="top"
             android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:layout_marginBottom="@dimen/notification_action_list_height"
             android:clipToPadding="false"
             android:orientation="vertical">
 
@@ -61,7 +63,7 @@
                 android:id="@+id/notification_material_reply_container"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
-        <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
+    <include layout="@layout/notification_material_action_list" />
     <include layout="@layout/notification_template_right_icon" />
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_inbox.xml b/core/res/res/layout/notification_template_material_inbox.xml
index 0e93d0b..7820e39 100644
--- a/core/res/res/layout/notification_template_material_inbox.xml
+++ b/core/res/res/layout/notification_template_material_inbox.xml
@@ -23,6 +23,7 @@
     >
     <include layout="@layout/notification_template_header" />
     <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="top"
@@ -117,7 +118,7 @@
                 android:id="@+id/notification_material_reply_container"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />
-        <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
+    <include layout="@layout/notification_material_action_list" />
     <include layout="@layout/notification_template_right_icon" />
 </FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index d95ff05..07b1100 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -22,6 +22,7 @@
     >
     <include layout="@layout/notification_template_header" />
     <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="top"
@@ -74,7 +75,7 @@
                     />
             </com.android.internal.widget.MessagingLinearLayout>
         </LinearLayout>
-        <include layout="@layout/notification_material_action_list" />
     </LinearLayout>
+    <include layout="@layout/notification_material_action_list" />
     <include layout="@layout/notification_template_right_icon" />
 </FrameLayout>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e68003c..59447c3 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -800,8 +800,8 @@
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Tillader, at appen kan indstille en alarm i en installeret alarmapp. Nogle alarmapps har muligvis ikke denne funktion."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføje telefonsvarer"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string>
-    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string>
+    <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geoplacering i Browser"</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geoplacering. Ondsindede apps kan benytte dette til at sende oplysninger om sted til vilkårlige websites."</string>
     <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index ec0ed60..dc30013 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -525,11 +525,11 @@
     <string name="policylab_resetPassword" msgid="4934707632423915395">"Displaysperre ändern"</string>
     <string name="policydesc_resetPassword" msgid="1278323891710619128">"Displaysperre ändern"</string>
     <string name="policylab_forceLock" msgid="2274085384704248431">"Bildschirm sperren"</string>
-    <string name="policydesc_forceLock" msgid="1141797588403827138">"Lege fest, wie und wann der Bildschirm gesperrt wird."</string>
+    <string name="policydesc_forceLock" msgid="1141797588403827138">"Festlegen, wie und wann der Bildschirm gesperrt wird"</string>
     <string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
     <string name="policydesc_wipeData" product="tablet" msgid="4306184096067756876">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Tablet ohne Warnung löschen"</string>
     <string name="policydesc_wipeData" product="tv" msgid="5816221315214527028">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Fernseher ohne Warnung löschen"</string>
-    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Setze das Telefon auf die Werkseinstellungen zurück. Dabei werden alle Daten ohne Warnung gelöscht."</string>
+    <string name="policydesc_wipeData" product="default" msgid="5096895604574188391">"Auf Werkseinstellungen zurücksetzen und damit Daten auf dem Telefon ohne Warnung löschen"</string>
     <string name="policylab_wipeData_secondaryUser" msgid="8362863289455531813">"Nutzerdaten löschen"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="6336255514635308054">"Daten dieses Nutzers auf diesem Tablet ohne vorherige Warnung löschen"</string>
     <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2086473496848351810">"Daten dieses Nutzers auf diesem Fernseher ohne vorherige Warnung löschen"</string>
@@ -543,7 +543,7 @@
     <string name="policylab_disableCamera" msgid="6395301023152297826">"Kameras deaktivieren"</string>
     <string name="policydesc_disableCamera" msgid="2306349042834754597">"Nutzung sämtlicher Gerätekameras unterbinden"</string>
     <string name="policylab_disableKeyguardFeatures" msgid="8552277871075367771">"Einige Funktionen der Displaysperre deaktivieren"</string>
-    <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Verhindert die Verwendung einiger Funktionen der Displaysperre"</string>
+    <string name="policydesc_disableKeyguardFeatures" msgid="2044755691354158439">"Verwendung einiger Funktionen der Displaysperre verhindern"</string>
   <string-array name="phoneTypes">
     <item msgid="8901098336658710359">"Privat"</item>
     <item msgid="869923650527136615">"Mobil"</item>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index e010753..d9aac5a 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -228,9 +228,9 @@
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Անձայն ռեժիմ"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Ձայնը անջատված է"</string>
     <string name="global_action_silent_mode_off_status" msgid="1506046579177066419">"Ձայնը միացված է"</string>
-    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռային ռեժիմ"</string>
-    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռային ռեժիմը միացված է"</string>
-    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռային ռեժիմը անջատված է"</string>
+    <string name="global_actions_toggle_airplane_mode" msgid="5884330306926307456">"Ինքնաթիռի ռեժիմ"</string>
+    <string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Ինքնաթիռի ռեժիմը միացված է"</string>
+    <string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Ինքնաթիռի ռեժիմը անջատված է"</string>
     <string name="global_action_settings" msgid="1756531602592545966">"Կարգավորումներ"</string>
     <string name="global_action_assist" msgid="3892832961594295030">"Օգնական"</string>
     <string name="global_action_voice_assist" msgid="7751191495200504480">"Ձայնային օգնութ"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 013fae6..0e4c1d6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -344,11 +344,11 @@
     <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Leidžiama programai keisti duomenis apie telefone saugomus kontaktus, įskaitant dažnį, kuriuo konkretiems asmenims skambinote, siuntėte el. laiškus ar bendravote kitais būdais. Šis leidimas suteikia teisę programoms ištrinti kontaktinius duomenis."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"skaityti skambučių žurnalą"</string>
     <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Leidžiama programai skaityti planšetinio kompiuterio skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Šis leidimas suteikia teisę programai išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti skambučių žurnalą be jūsų žinios."</string>
-    <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Programai leidžiama nuskaityti TV skambučių žurnalą, įskaitant duomenis apie gaunamus arba siunčiamus skambučius. Dėl šio leidimo programoms leidžiama išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti šiuos duomenis be jūsų žinios."</string>
+    <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Programai leidžiama nuskaityti TV skambučių žurnalą, įskaitant duomenis apie gaunamuosius arba siunčiamuosius skambučius. Dėl šio leidimo programoms leidžiama išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti šiuos duomenis be jūsų žinios."</string>
     <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Leidžiama programai skaityti telefono skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Šis leidimas suteikia teisę programai išsaugoti skambučių žurnalo duomenis, o kenkėjiškos programos gali bendrinti skambučių žurnalą be jūsų žinios."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"rašyti skambučių žurnalą"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Programai leidžiama skaityti planšetinio kompiuterio skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Kenkėjiškos programos tai gali naudoti, kad ištrintų ar keistų jūsų skambučių žurnalą."</string>
-    <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Programai leidžiama keisti TV skambučių žurnalą, įskaitant duomenis apie gaunamus ir siunčiamus skambučius. Taip kenkėjiškos programos gali ištrinti arba pakeisti skambučių žurnalą."</string>
+    <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Programai leidžiama keisti TV skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Taip kenkėjiškos programos gali ištrinti arba pakeisti skambučių žurnalą."</string>
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"Programai leidžiama skaityti telefono skambučių žurnalą, įskaitant duomenis apie gaunamuosius ir siunčiamuosius skambučius. Kenkėjiškos programos tai gali naudoti, kad ištrintų ar keistų jūsų skambučių žurnalą."</string>
     <string name="permlab_bodySensors" msgid="4683341291818520277">"pas. k. jut. (pvz., pul. dažn. st. įr.)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"Programai leidžiama pasiekti duomenis, gautus iš jutiklių, stebinčių fizinę būseną, pvz., širdies ritmą."</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index 7159f1f..ae9b7ef 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -395,9 +395,9 @@
     <string name="permdesc_setTimeZone" product="tv" msgid="888864653946175955">"Апп-д телевизийн цагийн бүсийг өөрчлөхийг зөвшөөрдөг."</string>
     <string name="permdesc_setTimeZone" product="default" msgid="4499943488436633398">"Апп нь утасны цагийн бүсийг өөрчлөх боломжтой."</string>
     <string name="permlab_getAccounts" msgid="1086795467760122114">"төхөөрөмж дээрх акаунтыг олох"</string>
-    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Апп нь таблетэд мэдэгдэж байгаа акаунтын жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
+    <string name="permdesc_getAccounts" product="tablet" msgid="2741496534769660027">"Апп нь таблетэд мэдэгдэж байгаа бүртгэлийн жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
     <string name="permdesc_getAccounts" product="tv" msgid="4190633395633907543">"Телевизийн жагсаалтад байгаа акаунтуудын хаягийг апп-д авахыг зөвшөөрдөг. Энэ нь таны суулгасан бусад аппликэйшнүүдийн бий болгосон акаунтуудыг оруулж болно."</string>
-    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Апп нь утсанд мэдэгдэж байгаа акаунтын жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
+    <string name="permdesc_getAccounts" product="default" msgid="3448316822451807382">"Апп нь утсанд мэдэгдэж байгаа бүртгэлийн жагсаалтыг авах боломжтой. Энд таны суулгасан аппликешнүүдийн үүсгэсэн бүх акаунтууд хамрагдана."</string>
     <string name="permlab_accessNetworkState" msgid="4951027964348974773">"сүлжээний холболтыг үзэх"</string>
     <string name="permdesc_accessNetworkState" msgid="8318964424675960975">"Апп нь сүлжээ байгаа болон холбогдсон эсэх зэрэг сүлжээний холболтын талаарх мэдээллийг харах боломжтой."</string>
     <string name="permlab_createNetworkSockets" msgid="7934516631384168107">"сүлжээнд бүрэн нэвтрэх"</string>
@@ -454,11 +454,11 @@
   </string-array>
     <string name="fingerprint_icon_content_description" msgid="2340202869968465936">"Хурууны хээний дүрс"</string>
     <string name="permlab_readSyncSettings" msgid="6201810008230503052">"синк тохиргоог унших"</string>
-    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь акаунтын синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп акаунттай синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
+    <string name="permdesc_readSyncSettings" msgid="2706745674569678644">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
     <string name="permlab_writeSyncSettings" msgid="5408694875793945314">"синкийг унтрааж асаах тохиргоо"</string>
-    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Апп нь акаунтын синк тохиргоог өөрчлөх боломжтой. Жишээ нь энэ нь Хүмүүс апп акаунттай синк хийхийг идэвхжүүлэх боломжтой."</string>
+    <string name="permdesc_writeSyncSettings" msgid="8956262591306369868">"Апп нь бүртгэлийн синк тохиргоог өөрчлөх боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийхийг идэвхжүүлэх боломжтой."</string>
     <string name="permlab_readSyncStats" msgid="7396577451360202448">"синк статистикийг унших"</string>
-    <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Апп нь синк үйлдэлийн түүх болон хэр их дата синк хийгдсэн зэрэг акаунтын синк статусыг унших боломжтой."</string>
+    <string name="permdesc_readSyncStats" msgid="1510143761757606156">"Апп нь синк үйлдэлийн түүх болон хэр их дата синк хийгдсэн зэрэг бүртгэлийн синк статусыг унших боломжтой."</string>
     <string name="permlab_sdcardRead" product="nosdcard" msgid="367275095159405468">"таны USB сангийн агуулгыг унших боломжтой"</string>
     <string name="permlab_sdcardRead" product="default" msgid="2188156462934977940">"таны SD картны агуулгыг унших боломжтой"</string>
     <string name="permdesc_sdcardRead" product="nosdcard" msgid="3446988712598386079">"Апп нь таны USB сангийн агуулгыг унших боломжтой."</string>
@@ -1261,7 +1261,7 @@
     <string name="gpsVerifYes" msgid="2346566072867213563">"Тийм"</string>
     <string name="gpsVerifNo" msgid="1146564937346454865">"Үгүй"</string>
     <string name="sync_too_many_deletes" msgid="5296321850662746890">"Устгах хязгаар хэтрэв"</string>
-    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>-р <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> акаунтын <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> зүйл устсан . Та юу хиймээр байна?"</string>
+    <string name="sync_too_many_deletes_desc" msgid="496551671008694245">"<xliff:g id="TYPE_OF_SYNC">%2$s</xliff:g>-р <xliff:g id="ACCOUNT_NAME">%3$s</xliff:g> бүртгэлийн <xliff:g id="NUMBER_OF_DELETED_ITEMS">%1$d</xliff:g> зүйл устсан . Та юу хиймээр байна?"</string>
     <string name="sync_really_delete" msgid="2572600103122596243">"Устгах"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Устгасныг буцаах"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Одоо юу ч хийхгүй"</string>
@@ -1412,7 +1412,7 @@
     <string name="kg_failed_attempts_now_wiping" product="default" msgid="4817627474419471518">"Та утсыг тайлах гэж <xliff:g id="NUMBER">%d</xliff:g> удаа буруу оролдлоо. Утас одоо үйлдвэрийн үндсэн утгаараа тохируулагдах болно."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та таблетаа тайлахын тулд имэйл бүртгэл шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_failed_attempts_almost_at_login" product="tv" msgid="4224651132862313471">"Та зурган түгжээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу оруулсан байна. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа буруу оруулсны дараагаар та телевизийнхээ түгжээг и-мэйл дансаа ашиглан тайлах хэрэгтэй болно.\n\n Та <xliff:g id="NUMBER_2">%3$d</xliff:g> секундийн дараа дахин оролдоно уу."</string>
-    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл акаунтаа ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
+    <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл бүртгэлээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"Устгах"</string>
     <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Дууг санал болгосноос чанга болгож өсгөх үү?\n\nУрт хугацаанд чанга хөгжим сонсох нь таны сонсголыг муутгаж болно."</string>
diff --git a/core/res/res/values-watch/dimens.xml b/core/res/res/values-notround-watch/dimens.xml
similarity index 100%
rename from core/res/res/values-watch/dimens.xml
rename to core/res/res/values-notround-watch/dimens.xml
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-notround-watch/dimens_material.xml
similarity index 67%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/values-notround-watch/dimens_material.xml
index 8dbc905..b02437b 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-notround-watch/dimens_material.xml
@@ -14,7 +14,10 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+    <dimen name="dialog_padding_material">8dp</dimen>
+    <dimen name="preference_fragment_padding_vertical_material">0dp</dimen>
+
+    <dimen name="list_item_padding_horizontal_material">16dp</dimen>
+    <dimen name="list_item_padding_start_material">16dp</dimen>
+    <dimen name="list_item_padding_end_material">16dp</dimen>
 </resources>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-notround-watch/styles_material.xml
similarity index 75%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/values-notround-watch/styles_material.xml
index 8dbc905..cd8521f4 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-notround-watch/styles_material.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!-- Copyright (C) 2016 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,5 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+    <style name="TextAppearance.Material.AlertDialogMessage" parent="TextAppearance.Material.Body1"/>
 </resources>
diff --git a/core/res/res/values-notround/dimens_micro.xml b/core/res/res/values-notround/dimens_micro.xml
deleted file mode 100644
index 51291d9..0000000
--- a/core/res/res/values-notround/dimens_micro.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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>
-    <dimen name="dialog_padding_micro">8dp</dimen>
-    <dimen name="list_item_padding_left_micro">16dp</dimen>
-    <dimen name="list_item_padding_right_micro">16dp</dimen>
-</resources>
diff --git a/core/res/res/values-notround/styles_micro.xml b/core/res/res/values-notround/styles_micro.xml
deleted file mode 100644
index 1294660..0000000
--- a/core/res/res/values-notround/styles_micro.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small">
-        <item name="textAlignment">viewStart</item>
-    </style>
-    <style name="PreferenceFragment.Micro" parent="PreferenceFragment.Material"/>
-    <style name="PreferenceFragmentList.Micro" parent="PreferenceFragmentList.Material"/>
-</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index b5d87f7..1530b4f 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -245,19 +245,19 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"aceder aos contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localização"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"aceda à localização do seu dispositivo"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"aceder à localização do seu dispositivo"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendário"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"aceda ao calendário"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"aceder ao calendário"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"envie e veja mensagens SMS"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"aceda a fotos, multimédia e ficheiros no dispositivo"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"aceder a fotos, multimédia e ficheiros no dispositivo"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"gravar áudio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmara"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"tirar fotografias e gravar vídeos"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telemóvel"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gira chamadas"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerir chamadas"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores de corpo"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"aceder a dados do sensor acerca dos seus sinais vitais"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Obter conteúdo da janela"</string>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-round-watch/config_material.xml
similarity index 66%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/values-round-watch/config_material.xml
index 8dbc905..bf445ef 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-round-watch/config_material.xml
@@ -13,8 +13,10 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+
+<!-- These resources are around just to allow their values to be customized
+     for watch products.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Don't clip on round screens so the list can scroll past the rounded edges. -->
+    <bool name="config_preferenceFragmentClipToPadding">false</bool>
 </resources>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-round-watch/dimens_material.xml
similarity index 67%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/values-round-watch/dimens_material.xml
index 8dbc905..a417d19 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-round-watch/dimens_material.xml
@@ -14,7 +14,10 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+    <dimen name="dialog_padding_material">32dp</dimen>
+    <dimen name="preference_fragment_padding_vertical_material">22dp</dimen>
+
+    <dimen name="list_item_padding_horizontal_material">32dp</dimen>
+    <dimen name="list_item_padding_start_material">40dp</dimen>
+    <dimen name="list_item_padding_end_material">24dp</dimen>
 </resources>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-round-watch/styles_material.xml
similarity index 75%
copy from core/res/res/values-round/dimens_micro.xml
copy to core/res/res/values-round-watch/styles_material.xml
index 8dbc905..a2f3c02 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-round-watch/styles_material.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <!-- Copyright (C) 2016 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+    <style name="TextAppearance.Material.AlertDialogMessage" parent="TextAppearance.Material.Body1">
+        <item name="textAlignment">center</item>
+    </style>
 </resources>
diff --git a/core/res/res/values-round/styles_micro.xml b/core/res/res/values-round/styles_micro.xml
deleted file mode 100644
index f19adde..0000000
--- a/core/res/res/values-round/styles_micro.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small">
-        <item name="textAlignment">center</item>
-    </style>
-    <style name="PreferenceFragment.Micro" parent="PreferenceFragment.Material">
-        <item name="paddingTop">22dp</item>
-        <item name="paddingBottom">22dp</item>
-        <item name="clipToPadding">false</item>
-    </style>
-    <style name="PreferenceFragmentList.Micro" parent="PreferenceFragmentList.Material">
-        <item name="paddingTop">22dp</item>
-        <item name="paddingBottom">22dp</item>
-    </style>
-</resources>
diff --git a/core/res/res/values/colors_micro.xml b/core/res/res/values-watch/colors_material.xml
similarity index 64%
rename from core/res/res/values/colors_micro.xml
rename to core/res/res/values-watch/colors_material.xml
index b268e9a..cbdf879 100644
--- a/core/res/res/values/colors_micro.xml
+++ b/core/res/res/values-watch/colors_material.xml
@@ -14,21 +14,14 @@
      limitations under the License.
 -->
 <resources>
-    <color name="foreground_micro_dark">@color/white</color>
-    <color name="foreground_micro_light">@color/black</color>
+    <color name="background_material_dark">@color/micro_blue_grey_b15</color>
+    <color name="background_floating_material_dark">@color/micro_blue_grey_b30</color>
 
-    <color name="background_micro_dark">@color/micro_blue_grey_b15</color>
-    <color name="background_micro_light">@color/white</color>
-    <color name="background_floating_micro_dark">@color/micro_blue_grey_b30</color>
-    <color name="background_floating_micro_light">@color/micro_blue_grey_500</color>
+    <color name="primary_material_dark">@color/micro_blue_grey_b65</color>
+    <color name="primary_dark_material_dark">@color/micro_blue_grey_b40</color>
 
-    <color name="primary_micro_dark">@color/micro_blue_grey_b65</color>
-    <color name="primary_dark_micro_dark">@color/micro_blue_grey_b40</color>
-
-    <color name="accent_micro_light">@color/micro_blue_grey_500</color>
-    <color name="accent_micro_dark">@color/micro_blue_grey_b100</color>
-
-    <color name="button_micro_dark">@color/micro_button_gray</color>
+    <color name="accent_material_dark">@color/micro_blue_grey_b100</color>
+    <color name="accent_material_light">@color/micro_blue_grey_500</color>
 
     <!-- Primary & accent colors -->
     <eat-comment />
diff --git a/core/res/res/values-watch/config_material.xml b/core/res/res/values-watch/config_material.xml
new file mode 100644
index 0000000..951c088
--- /dev/null
+++ b/core/res/res/values-watch/config_material.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for watch products.  Do not translate. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Watch type devices have limited screen real-estate, and thus action bars should not be
+         used. -->
+    <bool name="config_windowActionBarSupported">false</bool>
+
+    <!-- Watch type devices have limited screen real-estate, and thus titles should not be used. -->
+    <bool name="config_windowNoTitleDefault">true</bool>
+
+    <!-- Use micro alert controller -->
+    <integer name="config_alertDialogController">1</integer>
+
+    <!-- Dialog windows in watch should occupy the whole screen and not be floating. -->
+    <bool name="config_dialogWindowIsFloating">false</bool>
+
+    <!-- Always overscan by default to ensure onApplyWindowInsets will always be called. -->
+    <bool name="config_windowOverscanByDefault">true</bool>
+
+    <!-- Due to the smaller screen size, have dialog titles occupy more than 1 line. -->
+    <integer name="config_dialogWindowTitleMaxLines">3</integer>
+</resources>
diff --git a/core/res/res/values-round/dimens_micro.xml b/core/res/res/values-watch/dimens_material.xml
similarity index 79%
rename from core/res/res/values-round/dimens_micro.xml
rename to core/res/res/values-watch/dimens_material.xml
index 8dbc905..d579434 100644
--- a/core/res/res/values-round/dimens_micro.xml
+++ b/core/res/res/values-watch/dimens_material.xml
@@ -14,7 +14,5 @@
      limitations under the License.
 -->
 <resources>
-    <dimen name="dialog_padding_micro">32dp</dimen>
-    <dimen name="list_item_padding_left_micro">40dp</dimen>
-    <dimen name="list_item_padding_right_micro">24dp</dimen>
+    <item name="text_line_spacing_multiplier_material" format="float" type="dimen">1.2</item>
 </resources>
diff --git a/core/res/res/values-watch/donottranslate_material.xml b/core/res/res/values-watch/donottranslate_material.xml
new file mode 100644
index 0000000..a6f2ff4
--- /dev/null
+++ b/core/res/res/values-watch/donottranslate_material.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT 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>
+    <string name="font_family_display_4_material">sans-serif-condensed-light</string>
+    <string name="font_family_display_3_material">sans-serif-condensed-light</string>
+    <string name="font_family_display_2_material">sans-serif-condensed-light</string>
+    <string name="font_family_display_1_material">sans-serif-condensed-light</string>
+    <string name="font_family_headline_material">sans-serif-condensed-light</string>
+    <string name="font_family_title_material">sans-serif-condensed</string>
+    <string name="font_family_subhead_material">sans-serif-condensed-light</string>
+    <string name="font_family_menu_material">sans-serif-condensed-light</string>
+    <string name="font_family_body_2_material">sans-serif-condensed</string>
+    <string name="font_family_body_1_material">sans-serif-condensed-light</string>
+    <string name="font_family_caption_material">sans-serif-condensed-light</string>
+    <string name="font_family_button_material">sans-serif-condensed</string>
+ </resources>
diff --git a/core/res/res/values-watch/styles_material.xml b/core/res/res/values-watch/styles_material.xml
new file mode 100644
index 0000000..c19cc72
--- /dev/null
+++ b/core/res/res/values-watch/styles_material.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <style name="Animation.Material.Activity" parent="Animation.Activity">
+        <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
+        <item name="activityCloseEnterAnimation">@null</item>
+        <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
+        <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
+        <item name="taskCloseEnterAnimation">@null</item>
+        <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
+        <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
+        <item name="taskToBackEnterAnimation">@null</item>
+        <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
+        <item name="wallpaperOpenEnterAnimation">@null</item>
+        <item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
+        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
+        <item name="wallpaperIntraOpenEnterAnimation">@null</item>
+        <item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
+        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
+        <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
+    </style>
+
+    <style name="Widget.Material.TextView" parent="Widget.TextView">
+        <item name="breakStrategy">balanced</item>
+    </style>
+
+    <!-- Alert dialog button bar button -->
+    <style name="Widget.Material.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.Borderless.Small">
+        <item name="gravity">center_vertical|left</item>
+        <item name="minWidth">64dp</item>
+        <item name="minHeight">@dimen/alert_dialog_button_bar_height</item>
+    </style>
+
+    <style name="Widget.Material.NumberPicker" parent="Widget.NumberPicker">
+        <item name="internalLayout">@layout/number_picker_material</item>
+        <item name="solidColor">@color/transparent</item>
+        <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
+        <item name="selectionDividerHeight">2dp</item>
+        <item name="selectionDividersDistance">48dp</item>
+        <item name="internalMinWidth">64dp</item>
+        <item name="internalMaxHeight">180dp</item>
+        <item name="virtualButtonPressedDrawable">?selectableItemBackground</item>
+        <item name="descendantFocusability">blocksDescendants</item>
+    </style>
+
+    <!-- DO NOTE TRANSLATE Spans within this text are applied to style composing regions
+    within an EditText widget. The text content is ignored and not used.
+    Note: This is @color/material_deep_teal_200, cannot use @color references here. -->
+    <string name="candidates_style"><font color="#80cbc4">candidates</font></string>
+</resources>
diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml
index 6d6065f..04df180 100644
--- a/core/res/res/values-watch/themes.xml
+++ b/core/res/res/values-watch/themes.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -14,11 +14,10 @@
      limitations under the License.
 -->
 <resources>
-    <style name="Theme.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" />
-    <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.InputMethod" parent="Theme.Micro.InputMethod" />
-    <style name="Theme.Material.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
+    <!-- Theme for the dialog shown when an app crashes or ANRs. Override to make it dark. -->
+    <style name="Theme.Dialog.AppError" parent="Theme.DeviceDefault.Dialog.Alert">
+        <item name="windowContentTransitions">false</item>
+        <item name="windowActivityTransitions">false</item>
+        <item name="windowCloseOnTouchOutside">false</item>
+    </style>
 </resources>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 66509fb..2313b26 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -13,22 +13,31 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<resources>
-    <style name="Theme.DeviceDefault" parent="Theme.Micro" />
-    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Micro" />
-    <style name="Theme.DeviceDefault.Dialog" parent="Theme.Micro.Dialog" />
-    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Micro.Dialog" />
-    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Micro.InputMethod"  />
-    <style name="Theme.DeviceDefault.Panel" parent="Theme.Micro.Panel"  />
-    <style name="Theme.DeviceDefault.Light" parent="Theme.Micro.Light" />
-    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Micro.Light" />
-    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Micro.Light" />
-    <style name="Theme.DeviceDefault.Light.Dialog" parent="Theme.Micro.Dialog" />
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Micro.Dialog" />
-    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" />
-    <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Micro.Light.Panel"  />
-    <style name="Theme.DeviceDefault.Settings" parent="Theme.Micro" />
-    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Micro" />
-</resources>
 
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+This file contains the themes that are the Device Defaults.
+If you want to edit themes to skin your device, do it here.
+We recommend that you do not edit themes.xml and instead edit
+this file.
+
+Editing this file instead of themes.xml will greatly simplify
+merges for future platform versions and CTS compliance will be
+easier.
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <!-- Theme used for the intent picker activity. -->
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material">
+        <item name="colorControlActivated">?attr/colorControlHighlight</item>
+        <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+    </style>
+
+    <!-- Use a dark theme for watches. -->
+    <style name="Theme.DeviceDefault.System" parent="Theme.Material" />
+</resources>
diff --git a/core/res/res/values-watch/themes_material.xml b/core/res/res/values-watch/themes_material.xml
new file mode 100644
index 0000000..d92a947
--- /dev/null
+++ b/core/res/res/values-watch/themes_material.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!--
+===============================================================
+                        PLEASE READ
+===============================================================
+
+The Material themes must not be modified in order to pass CTS.
+Many related themes and styles depend on other values defined in this file.
+If you would like to provide custom themes and styles for your device,
+please see styles_device_defaults.xml.
+
+===============================================================
+                        PLEASE READ
+===============================================================
+ -->
+<resources>
+    <!-- Default theme for material style input methods, which is used by the
+         {@link android.inputmethodservice.InputMethodService} class.
+         this inherits from Theme.Panel, but sets up IME appropriate animations
+         and a few custom attributes. -->
+    <style name="Theme.Material.InputMethod" parent="Theme.Material.Panel">
+        <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
+        <item name="imeFullscreenBackground">?colorBackground</item>
+        <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
+    </style>
+</resources>
diff --git a/core/res/res/values/config_material.xml b/core/res/res/values/config_material.xml
new file mode 100644
index 0000000..f62678a
--- /dev/null
+++ b/core/res/res/values/config_material.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds, only for Material theme.  Do not translate.
+
+     NOTE: The naming convention is "config_camelCaseValue".  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- True if the device supports action bars. -->
+    <bool name="config_windowActionBarSupported">true</bool>
+
+    <!-- True if the device should have titles by default. -->
+    <bool name="config_windowNoTitleDefault">false</bool>
+
+    <!-- The alert controller to use for alert dialogs. -->
+    <integer name="config_alertDialogController">0</integer>
+
+    <!-- True if dialog windows are floating. -->
+    <bool name="config_dialogWindowIsFloating">true</bool>
+
+    <!-- True if windowOverscan should be on by default. -->
+    <bool name="config_windowOverscanByDefault">false</bool>
+
+    <!-- Max number of lines for the dialog title. -->
+    <integer name="config_dialogWindowTitleMaxLines">1</integer>
+
+    <!-- True if preference fragment should clip to padding. -->
+    <bool name="config_preferenceFragmentClipToPadding">true</bool>
+</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 37fb816..91d7227 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -148,12 +148,20 @@
     <!-- The margin on the start of the content view -->
     <dimen name="notification_content_margin_start">16dp</dimen>
 
-    <!-- The margin on the end of the content view -->
+    <!-- The margin on the end of the content view
+        Keep in sync with notification_content_plus_picture_margin! -->
     <dimen name="notification_content_margin_end">16dp</dimen>
 
-    <!-- The margin on the end of the content view with a picture.-->
+    <!-- The margin on the end of the content view with a picture.
+        Keep in sync with notification_content_plus_picture_margin! -->
     <dimen name="notification_content_picture_margin">56dp</dimen>
 
+    <!-- The margin on the end of the content view with a picture, plus the standard
+        content end margin.
+        Keep equal to (notification_content_picture_margin + notification_content_margin_end)!
+    -->
+    <dimen name="notification_content_plus_picture_margin_end">72dp</dimen>
+
     <!-- The height of the notification action list -->
     <dimen name="notification_action_list_height">56dp</dimen>
 
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 00e48a0..f96cef9 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -24,6 +24,8 @@
 
     <!-- Preference fragment padding, sides -->
     <dimen name="preference_fragment_padding_side_material">0dp</dimen>
+    <!-- Preference fragment padding, vertical -->
+    <dimen name="preference_fragment_padding_vertical_material">0dp</dimen>
 
     <!-- Preference breadcrumbs padding, start padding -->
     <dimen name="preference_breadcrumbs_padding_start_material">12dp</dimen>
@@ -53,6 +55,8 @@
     <!-- Default padding for list items. This should match the action bar
          content inset so that ListActivity items line up correctly. -->
     <dimen name="list_item_padding_horizontal_material">@dimen/action_bar_content_inset_material</dimen>
+    <dimen name="list_item_padding_start_material">@dimen/action_bar_content_inset_material</dimen>
+    <dimen name="list_item_padding_end_material">@dimen/action_bar_content_inset_material</dimen>
 
     <!-- Padding to add to the start of the overflow action button. -->
     <dimen name="action_bar_overflow_padding_start_material">6dp</dimen>
@@ -84,6 +88,8 @@
     <dimen name="text_size_medium_material">18sp</dimen>
     <dimen name="text_size_small_material">14sp</dimen>
 
+    <item name="text_line_spacing_multiplier_material" format="float" type="dimen">1.0</item>
+
     <dimen name="text_edit_floating_toolbar_elevation">2dp</dimen>
     <dimen name="text_edit_floating_toolbar_margin">20dp</dimen>
 
diff --git a/core/res/res/values/dimens_micro.xml b/core/res/res/values/dimens_micro.xml
deleted file mode 100644
index 75bbdec..0000000
--- a/core/res/res/values/dimens_micro.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT 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>
-    <dimen name="text_size_headline_micro">22sp</dimen>
-    <dimen name="text_size_title_micro">20sp</dimen>
-    <dimen name="text_size_subtitle_micro">18sp</dimen>
-    <dimen name="text_size_body_1_micro">16sp</dimen>
-    <dimen name="text_size_body_2_micro">14sp</dimen>
-    <dimen name="text_size_caption_micro">12sp</dimen>
-
-    <dimen name="text_size_large_micro">20sp</dimen>
-    <dimen name="text_size_medium_micro">18sp</dimen>
-    <dimen name="text_size_small_micro">16sp</dimen>
-
-    <item name="line_spacing_multiplier_micro" format="float" type="dimen">1.2</item>
-</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index bb07834..6e0ad36 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -40,7 +40,10 @@
         <item name="layout">@layout/preference_list_fragment_material</item>
         <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
         <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+        <item name="paddingTop">@dimen/preference_fragment_padding_vertical_material</item>
+        <item name="paddingBottom">@dimen/preference_fragment_padding_vertical_material</item>
         <item name="divider">?attr/listDivider</item>
+        <item name="clipToPadding">@bool/config_preferenceFragmentClipToPadding</item>
     </style>
 
     <style name="PreferenceActivity.Material">
@@ -134,6 +137,8 @@
     <style name="PreferenceFragmentList.Material">
         <item name="paddingStart">@dimen/preference_fragment_padding_side_material</item>
         <item name="paddingEnd">@dimen/preference_fragment_padding_side_material</item>
+        <item name="paddingTop">@dimen/preference_fragment_padding_vertical_material</item>
+        <item name="paddingBottom">@dimen/preference_fragment_padding_vertical_material</item>
     </style>
 
     <!-- Begin Material theme styles -->
@@ -147,6 +152,7 @@
         <item name="textColorLink">?attr/textColorLink</item>
         <item name="textSize">@dimen/text_size_body_1_material</item>
         <item name="fontFamily">@string/font_family_body_1_material</item>
+        <item name="lineSpacingMultiplier">@dimen/text_line_spacing_multiplier_material</item>
     </style>
 
     <style name="TextAppearance.Material.Display4">
@@ -1190,6 +1196,7 @@
         <item name="listItemLayout">@layout/select_dialog_item_material</item>
         <item name="multiChoiceItemLayout">@layout/select_dialog_multichoice_material</item>
         <item name="singleChoiceItemLayout">@layout/select_dialog_singlechoice_material</item>
+        <item name="controllerType">@integer/config_alertDialogController</item>
     </style>
 
     <style name="AlertDialog.Material.Light" />
@@ -1224,7 +1231,7 @@
     <style name="DialogWindowTitleBackground.Material.Light" />
 
     <style name="DialogWindowTitle.Material">
-        <item name="maxLines">1</item>
+        <item name="maxLines">@integer/config_dialogWindowTitleMaxLines</item>
         <item name="scrollHorizontally">true</item>
         <item name="textAppearance">@style/TextAppearance.Material.DialogWindowTitle</item>
     </style>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
deleted file mode 100644
index 75f602b..0000000
--- a/core/res/res/values/styles_micro.xml
+++ /dev/null
@@ -1,186 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <!-- Preference styles -->
-    <eat-comment/>
-    <style name="Preference.Micro" parent="Preference.Material">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.CheckBoxPreference" parent="Preference.Material.CheckBoxPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.SwitchPreference" parent="Preference.Material.SwitchPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.PreferenceScreen" parent="Preference.Material.PreferenceScreen">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.DialogPreference" parent="Preference.Material.DialogPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.DialogPreference.YesNoPreference" parent="Preference.Material.DialogPreference.YesNoPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.DialogPreference.SeekBarPreference" parent="Preference.Material.DialogPreference.SeekBarPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.DialogPreference.EditTextPreference" parent="Preference.Material.DialogPreference.EditTextPreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-    <style name="Preference.Micro.RingtonePreference" parent="Preference.Material.RingtonePreference">
-        <item name="layout">@layout/preference_micro</item>
-    </style>
-
-    <style name="Animation.Micro"/>
-
-    <style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
-        <item name="activityOpenEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="activityOpenExitAnimation">@anim/slide_in_exit_micro</item>
-        <item name="activityCloseEnterAnimation">@null</item>
-        <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskOpenEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="taskOpenExitAnimation">@anim/slide_in_exit_micro</item>
-        <item name="taskCloseEnterAnimation">@null</item>
-        <item name="taskCloseExitAnimation">@anim/slide_out_micro</item>
-        <item name="taskToFrontEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="taskToFrontExitAnimation">@anim/slide_in_exit_micro</item>
-        <item name="taskToBackEnterAnimation">@null</item>
-        <item name="taskToBackExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperOpenEnterAnimation">@null</item>
-        <item name="wallpaperOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperCloseEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="wallpaperCloseExitAnimation">@anim/slide_in_exit_micro</item>
-        <item name="wallpaperIntraOpenEnterAnimation">@null</item>
-        <item name="wallpaperIntraOpenExitAnimation">@anim/slide_out_micro</item>
-        <item name="wallpaperIntraCloseEnterAnimation">@anim/slide_in_enter_micro</item>
-        <item name="wallpaperIntraCloseExitAnimation">@anim/slide_in_exit_micro</item>
-    </style>
-
-    <style name="AlertDialog.Micro" parent="AlertDialog.Material">
-        <item name="fullDark">@null</item>
-        <item name="topDark">@null</item>
-        <item name="centerDark">@null</item>
-        <item name="bottomDark">@null</item>
-        <item name="fullBright">@null</item>
-        <item name="topBright">@null</item>
-        <item name="centerBright">@null</item>
-        <item name="bottomBright">@null</item>
-        <item name="bottomMedium">@null</item>
-        <item name="centerMedium">@null</item>
-        <item name="layout">@layout/alert_dialog_micro</item>
-        <item name="controllerType">micro</item>
-    </style>
-
-    <style name="DialogWindowTitle.Micro">
-        <item name="scrollHorizontally">true</item>
-        <item name="textAppearance">@style/TextAppearance.Micro.DialogWindowTitle</item>
-        <item name="textAlignment">viewStart</item>
-    </style>
-
-    <style name="TextAppearance.Micro" parent="TextAppearance.Material">
-        <item name="fontFamily">sans-serif-condensed-light</item>
-        <item name="lineSpacingMultiplier">@dimen/line_spacing_multiplier_micro</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textSize">@dimen/text_size_medium_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Inverse" parent="TextAppearance.Material">
-        <item name="textColor">?attr/textColorPrimaryInverse</item>
-        <item name="textColorHint">?attr/textColorHintInverse</item>
-        <item name="textColorHighlight">?attr/textColorHighlightInverse</item>
-        <item name="textColorLink">?attr/textColorLinkInverse</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Headline">
-        <item name="textSize">@dimen/text_size_headline_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Title">
-        <item name="textSize">@dimen/text_size_title_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Subtitle">
-        <item name="textSize">@dimen/text_size_subtitle_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Body1">
-        <item name="textSize">@dimen/text_size_body_1_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Body2">
-        <item name="textSize">@dimen/text_size_body_2_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Caption">
-        <item name="textSize">@dimen/text_size_caption_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Large">
-        <item name="textSize">@dimen/text_size_large_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Medium">
-        <item name="textSize">@dimen/text_size_medium_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.Small">
-        <item name="textSize">@dimen/text_size_small_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.DialogWindowTitle" parent="TextAppearance.Material.DialogWindowTitle">
-        <item name="fontFamily">sans-serif-condensed-light</item>
-        <item name="lineSpacingMultiplier">@dimen/line_spacing_multiplier_micro</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textSize">@dimen/text_size_large_micro</item>
-    </style>
-
-    <style name="TextAppearance.Micro.AlertDialog.Message" parent="TextAppearance.Micro.Small" />
-
-    <style name="Widget.Micro" parent="Widget.Material" />
-
-    <style name="Widget.Micro.TextView" parent="Widget.Material.TextView" >
-        <item name="breakStrategy">balanced</item>
-        <item name="hyphenationFrequency">normal</item>
-    </style>
-
-    <style name="Widget.Micro.EditText" parent="Widget.Material.EditText">
-        <item name="android:breakStrategy">simple</item>
-    </style>
-
-    <style name="Widget.Micro.NumberPicker">
-        <item name="internalLayout">@layout/number_picker_with_selector_wheel_micro</item>
-        <item name="solidColor">@color/transparent</item>
-        <item name="selectionDivider">@drawable/numberpicker_selection_divider</item>
-        <item name="selectionDividerHeight">0dip</item>
-        <item name="selectionDividersDistance">104dip</item>
-        <item name="internalMinWidth">64dip</item>
-        <item name="internalMaxHeight">180dip</item>
-        <item name="virtualButtonPressedDrawable">?attr/selectableItemBackground</item>
-        <item name="descendantFocusability">blocksDescendants</item>
-    </style>
-
-    <style name="Widget.Micro.ButtonBar">
-        <item name="background">@color/background_floating_micro_dark</item>
-    </style>
-
-    <style name="Widget.Micro.Button.ButtonBar.AlertDialog" parent="Widget.Material.Button.ButtonBar.AlertDialog">
-        <item name="textAppearance">@style/TextAppearance.Micro.Small</item>
-        <item name="maxLines">3</item>
-        <item name="textColor">?attr/textColorPrimary</item>
-        <item name="textAlignment">viewStart</item>
-    </style>
-</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index f4da457..6e937ff 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1863,7 +1863,6 @@
   <java-symbol type="string" name="vpn_lockdown_config" />
   <java-symbol type="string" name="wallpaper_binding_label" />
   <java-symbol type="style" name="Theme.Dialog.AppError" />
-  <java-symbol type="style" name="Theme.Micro.Dialog.Alert" />
   <java-symbol type="style" name="Theme.Leanback.Dialog.Alert" />
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
@@ -2189,6 +2188,7 @@
   <java-symbol type="style" name="TextAppearance.Material.TimePicker.TimeLabel" />
   <java-symbol type="attr" name="seekBarPreferenceStyle" />
   <java-symbol type="style" name="Theme.DeviceDefault.Resolver" />
+  <java-symbol type="style" name="Theme.DeviceDefault.System" />
   <java-symbol type="attr" name="preferenceActivityStyle" />
   <java-symbol type="attr" name="preferenceFragmentStyle" />
   <java-symbol type="bool" name="skipHoldBeforeMerge" />
@@ -2608,6 +2608,9 @@
 
   <java-symbol type="bool" name="config_supportPreRebootSecurityLogs" />
 
+  <java-symbol type="dimen" name="notification_content_plus_picture_margin_end" />
+  <java-symbol type="id" name="notification_action_list_margin_target" />
+
   <!-- Pinner Service -->
   <java-symbol type="array" name="config_defaultPinnerServiceFiles" />
 
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aecda44..998eea5 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -174,6 +174,7 @@
 
         <!-- Window attributes -->
         <item name="windowBackground">@drawable/screen_background_selector_dark</item>
+        <item name="windowBackgroundFallback">?attr/colorBackground</item>
         <item name="windowClipToOutline">false</item>
         <item name="windowFrame">@null</item>
         <item name="windowNoTitle">false</item>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 11bb106..ea1b626 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -551,4 +551,6 @@
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
     </style>
 
+    <!-- DeviceDefault theme for the default system theme.  -->
+    <style name="Theme.DeviceDefault.System" parent="Theme.Material.Light.DarkActionBar" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 2ea5c5e..0e4e060 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -119,8 +119,8 @@
         <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
         <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_horizontal_material</item>
-        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_horizontal_material</item>
-        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_horizontal_material</item>
+        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_start_material</item>
+        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_end_material</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -153,9 +153,9 @@
         <item name="windowBackground">?attr/colorBackground</item>
         <item name="windowClipToOutline">true</item>
         <item name="windowFrame">@null</item>
-        <item name="windowNoTitle">false</item>
+        <item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
         <item name="windowFullscreen">false</item>
-        <item name="windowOverscan">false</item>
+        <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -164,7 +164,7 @@
         <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
         <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
-        <item name="windowActionBar">true</item>
+        <item name="windowActionBar">@bool/config_windowActionBarSupported</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
         <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
@@ -480,8 +480,8 @@
         <item name="textAppearanceListItemSecondary">@style/TextAppearance.Material.Body1</item>
         <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_horizontal_material</item>
         <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_horizontal_material</item>
-        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_horizontal_material</item>
-        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_horizontal_material</item>
+        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_start_material</item>
+        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_end_material</item>
 
         <!-- @hide -->
         <item name="searchResultListItemHeight">58dip</item>
@@ -514,9 +514,9 @@
         <item name="windowBackground">?attr/colorBackground</item>
         <item name="windowClipToOutline">true</item>
         <item name="windowFrame">@null</item>
-        <item name="windowNoTitle">false</item>
+        <item name="windowNoTitle">@bool/config_windowNoTitleDefault</item>
         <item name="windowFullscreen">false</item>
-        <item name="windowOverscan">false</item>
+        <item name="windowOverscan">@bool/config_windowOverscanByDefault</item>
         <item name="windowIsFloating">false</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowShowWallpaper">false</item>
@@ -525,7 +525,7 @@
         <item name="windowTitleBackgroundStyle">@style/WindowTitleBackground.Material</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Activity</item>
         <item name="windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
-        <item name="windowActionBar">true</item>
+        <item name="windowActionBar">@bool/config_windowActionBarSupported</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
         <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
@@ -874,7 +874,7 @@
         <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
         <item name="windowBackground">@drawable/dialog_background_material</item>
         <item name="windowElevation">@dimen/floating_window_z</item>
-        <item name="windowIsFloating">true</item>
+        <item name="windowIsFloating">@bool/config_dialogWindowIsFloating</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
         <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
@@ -1080,7 +1080,7 @@
         <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
         <item name="windowBackground">@drawable/dialog_background_material</item>
         <item name="windowElevation">@dimen/floating_window_z</item>
-        <item name="windowIsFloating">true</item>
+        <item name="windowIsFloating">@bool/config_dialogWindowIsFloating</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
         <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
@@ -1090,10 +1090,10 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="listPreferredItemPaddingLeft">24dip</item>
-        <item name="listPreferredItemPaddingRight">24dip</item>
-        <item name="listPreferredItemPaddingStart">24dip</item>
-        <item name="listPreferredItemPaddingEnd">24dip</item>
+        <item name="listPreferredItemPaddingLeft">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingRight">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
 
         <item name="listDivider">@null</item>
 
@@ -1201,10 +1201,10 @@
 
         <item name="colorBackgroundCacheHint">@null</item>
 
-        <item name="listPreferredItemPaddingLeft">24dip</item>
-        <item name="listPreferredItemPaddingRight">24dip</item>
-        <item name="listPreferredItemPaddingStart">24dip</item>
-        <item name="listPreferredItemPaddingEnd">24dip</item>
+        <item name="listPreferredItemPaddingLeft">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingRight">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
+        <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
 
         <item name="listDivider">@null</item>
 
diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml
deleted file mode 100644
index e186c8b..0000000
--- a/core/res/res/values/themes_micro.xml
+++ /dev/null
@@ -1,165 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<resources>
-    <style name="Theme.MicroBase" parent="Theme.Material.NoActionBar">
-        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
-        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
-        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
-        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
-        <item name="editTextStyle">@style/Widget.Micro.EditText</item>
-        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@style/Animation.Micro.Activity</item>
-        <item name="windowBackground">@color/background_micro_dark</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowIsFloating">false</item>
-        <!-- Required to force windowInsets dispatch through application UI. -->
-        <item name="windowOverscan">true</item>
-
-        <item name="textAppearance">@style/TextAppearance.Micro</item>
-        <item name="textAppearanceInverse">@style/TextAppearance.Micro.Inverse</item>
-
-        <item name="textAppearanceLarge">@style/TextAppearance.Micro.Large</item>
-        <item name="textAppearanceMedium">@style/TextAppearance.Micro.Medium</item>
-        <item name="textAppearanceSmall">@style/TextAppearance.Micro.Small</item>
-
-        <item name="textAppearanceListItem">@style/TextAppearance.Micro.Body1</item>
-        <item name="textAppearanceListItemSmall">@style/TextAppearance.Micro.Body1</item>
-        <item name="textAppearanceListItemSecondary">@style/TextAppearance.Micro.Caption</item>
-        <item name="listPreferredItemPaddingLeft">@dimen/list_item_padding_left_micro</item>
-        <item name="listPreferredItemPaddingRight">@dimen/list_item_padding_right_micro</item>
-        <item name="listPreferredItemPaddingStart">@dimen/list_item_padding_left_micro</item>
-        <item name="listPreferredItemPaddingEnd">@dimen/list_item_padding_right_micro</item>
-
-        <!-- Dialog styling -->
-        <item name="buttonBarStyle">@style/Widget.Micro.ButtonBar</item>
-        <item name="buttonBarButtonStyle">@style/Widget.Micro.Button.ButtonBar.AlertDialog</item>
-
-        <!-- Color palette -->
-        <item name="colorPrimaryDark">@color/primary_dark_micro_dark</item>
-        <item name="colorPrimary">@color/primary_micro_dark</item>
-        <item name="colorAccent">@color/accent_micro_dark</item>
-        <item name="colorEdgeEffect">?attr/colorPrimary</item>
-
-        <!-- Preference styles -->
-        <item name="preferenceFragmentStyle">@style/PreferenceFragment.Micro</item>
-        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Micro</item>
-        <item name="preferenceStyle">@style/Preference.Micro</item>
-        <item name="preferenceScreenStyle">@style/Preference.Micro.PreferenceScreen</item>
-        <item name="checkBoxPreferenceStyle">@style/Preference.Micro.CheckBoxPreference</item>
-        <item name="switchPreferenceStyle">@style/Preference.Micro.SwitchPreference</item>
-        <item name="yesNoPreferenceStyle">@style/Preference.Micro.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@style/Preference.Micro.DialogPreference</item>
-        <item name="seekBarDialogPreferenceStyle">@style/Preference.Micro.DialogPreference.SeekBarPreference</item>
-        <item name="editTextPreferenceStyle">@style/Preference.Micro.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@style/Preference.Micro.RingtonePreference</item>
-    </style>
-
-    <style name="Theme.Micro" parent="Theme.MicroBase">
-    </style>
-
-    <style name="Theme.Micro.LightBase" parent="Theme.Material.Light.NoActionBar">
-        <item name="alertDialogTheme">@style/Theme.Micro.Dialog.Alert</item>
-        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
-        <item name="dialogTheme">@style/Theme.Micro.Dialog</item>
-        <item name="textViewStyle">@style/Widget.Micro.TextView</item>
-        <item name="numberPickerStyle">@style/Widget.Micro.NumberPicker</item>
-        <item name="windowAnimationStyle">@style/Animation.Micro.Activity</item>
-        <item name="windowBackground">@color/white</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowIsFloating">false</item>
-        <!-- Required to force windowInsets dispatch through application UI. -->
-        <item name="windowOverscan">true</item>
-
-        <!-- Preference styles -->
-        <item name="preferenceFragmentStyle">@style/PreferenceFragment.Micro</item>
-        <item name="preferenceFragmentListStyle">@style/PreferenceFragmentList.Micro</item>
-        <item name="preferenceStyle">@style/Preference.Micro</item>
-        <item name="preferenceScreenStyle">@style/Preference.Micro.PreferenceScreen</item>
-        <item name="checkBoxPreferenceStyle">@style/Preference.Micro.CheckBoxPreference</item>
-        <item name="switchPreferenceStyle">@style/Preference.Micro.SwitchPreference</item>
-        <item name="yesNoPreferenceStyle">@style/Preference.Micro.DialogPreference.YesNoPreference</item>
-        <item name="dialogPreferenceStyle">@style/Preference.Micro.DialogPreference</item>
-        <item name="seekBarDialogPreferenceStyle">@style/Preference.Micro.DialogPreference.SeekBarPreference</item>
-        <item name="editTextPreferenceStyle">@style/Preference.Micro.DialogPreference.EditTextPreference</item>
-        <item name="ringtonePreferenceStyle">@style/Preference.Micro.RingtonePreference</item>
-    </style>
-
-    <!-- Indirection needed for overlays to make sure there is a common base parent -->
-    <style name="Theme.Micro.Light" parent="Theme.Micro.LightBase">
-    </style>
-
-    <style name="Theme.Micro.DialogBase">
-        <item name="colorBackground">?attr/colorBackgroundFloating</item>
-
-        <item name="windowFrame">@null</item>
-        <item name="windowTitleBackgroundStyle">@style/DialogWindowTitleBackground.Material</item>
-        <item name="windowElevation">@dimen/floating_window_z</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowAnimationStyle">@style/Animation.Material.Dialog</item>
-        <item name="windowSoftInputMode">stateUnspecified|adjustPan</item>
-        <item name="windowActionBar">false</item>
-        <item name="windowActionModeOverlay">true</item>
-        <item name="windowCloseOnTouchOutside">@bool/config_closeDialogWhenTouchOutside</item>
-
-        <item name="colorBackgroundCacheHint">@null</item>
-
-        <item name="listDivider">@null</item>
-
-        <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
-
-        <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
-        <item name="windowIsFloating">false</item>
-        <item name="windowFullscreen">true</item>
-        <item name="windowBackground">@color/background_micro_dark</item>
-        <!-- Required to force windowInsets dispatch through application UI. -->
-        <item name="windowOverscan">true</item>
-    </style>
-
-    <!-- Indirection needed for overlays to make sure there is a common base parent -->
-    <style name="Theme.Micro.Dialog" parent="Theme.Micro.DialogBase">
-    </style>
-
-    <style name="Theme.Micro.Dialog.Alert">
-        <item name="windowTitleStyle">@style/DialogWindowTitle.Micro</item>
-        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
-        <item name="windowIsFloating">false</item>
-        <item name="windowOverscan">true</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
-    </style>
-
-    <style name="Theme.Micro.Dialog.AppError" parent="Theme.Micro.Dialog">
-        <item name="alertDialogStyle">@style/AlertDialog.Micro</item>
-        <item name="textAppearance">@style/TextAppearance.Micro.Large</item>
-        <item name="windowOverscan">true</item>
-        <item name="windowCloseOnTouchOutside">false</item>
-    </style>
-
-   <style name="Theme.Micro.Panel" parent="Theme.Material.Panel"  />
-   <style name="Theme.Micro.Light.Panel" parent="Theme.Material.Light.Panel"  />
-
-    <!-- Default theme for material style input methods, which is used by the
-         {@link android.inputmethodservice.InputMethodService} class.
-         This inherits from Theme.Panel, but sets up IME appropriate animations
-         and a few custom attributes. -->
-    <style name="Theme.Micro.InputMethod" parent="Theme.Micro.Panel">
-        <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
-        <item name="imeFullscreenBackground">#1e282c</item>
-        <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
-        <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
-    </style>
-</resources>
diff --git a/docs/html-intl/intl/es/training/material/compatibility.jd b/docs/html-intl/intl/es/training/material/compatibility.jd
index ad2e953..d2cb9aa 100644
--- a/docs/html-intl/intl/es/training/material/compatibility.jd
+++ b/docs/html-intl/intl/es/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>Dependencias</h3>
 
 <p>Para usar estas características en versiones de Android anteriores a la 5.0 (API nivel 21), incluye
-en tu proyecto la Biblioteca de soporte v7 de Android como una <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">dependencia de Gradle</a>:</p>
+en tu proyecto la Biblioteca de soporte v7 de Android como una <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependencia de Gradle</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/in/training/material/compatibility.jd b/docs/html-intl/intl/in/training/material/compatibility.jd
index d57c7be..ef444c3 100644
--- a/docs/html-intl/intl/in/training/material/compatibility.jd
+++ b/docs/html-intl/intl/in/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>Dependensi</h3>
 
 <p>Untuk menggunakan fitur-fitur ini di versi Android sebelum 5.0 (API level 21), sertakan
-Android v7 Support Library dalam proyek Anda sebagai <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">dependensi Gradle</a>:</p>
+Android v7 Support Library dalam proyek Anda sebagai <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependensi Gradle</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/ja/training/material/compatibility.jd b/docs/html-intl/intl/ja/training/material/compatibility.jd
index 0f8922f..2581170 100644
--- a/docs/html-intl/intl/ja/training/material/compatibility.jd
+++ b/docs/html-intl/intl/ja/training/material/compatibility.jd
@@ -122,7 +122,7 @@
 
 <h3>依存関係</h3>
 
-<p>5.0(API レベル 21)より前のバージョンの Android でこれらの機能を使用するには、Android v7 サポート ライブラリを <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle 依存関係</a>としてプロジェクトに含めます。
+<p>5.0(API レベル 21)より前のバージョンの Android でこれらの機能を使用するには、Android v7 サポート ライブラリを <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">Gradle 依存関係</a>としてプロジェクトに含めます。
 </p>
 
 <pre>
diff --git a/docs/html-intl/intl/ko/training/material/compatibility.jd b/docs/html-intl/intl/ko/training/material/compatibility.jd
index 266cd7c..5bb8434 100644
--- a/docs/html-intl/intl/ko/training/material/compatibility.jd
+++ b/docs/html-intl/intl/ko/training/material/compatibility.jd
@@ -122,7 +122,7 @@
 
 <h3>종속 사항</h3>
 
-<p>Android 5.0(API 레벨 21) 이전 버전에서 이러한 기능을 사용하려면 프로젝트에 Android v7 지원 라이브러리를 <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle 종속 사항</a>으로 포함합니다.
+<p>Android 5.0(API 레벨 21) 이전 버전에서 이러한 기능을 사용하려면 프로젝트에 Android v7 지원 라이브러리를 <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">Gradle 종속 사항</a>으로 포함합니다.
 </p>
 
 <pre>
diff --git a/docs/html-intl/intl/pt-br/training/material/compatibility.jd b/docs/html-intl/intl/pt-br/training/material/compatibility.jd
index 2540df1..d242c0c 100644
--- a/docs/html-intl/intl/pt-br/training/material/compatibility.jd
+++ b/docs/html-intl/intl/pt-br/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>Dependências</h3>
 
 <p>Para usar esses recursos em versões anteriores ao Android 5.0 (API de nível 21), inclua a
-Biblioteca de Suporte v7 do Android no projeto como uma <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">dependência de Gradle</a>:</p>
+Biblioteca de Suporte v7 do Android no projeto como uma <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">dependência de Gradle</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/ru/training/material/compatibility.jd b/docs/html-intl/intl/ru/training/material/compatibility.jd
index b7ca338..1f1d630 100644
--- a/docs/html-intl/intl/ru/training/material/compatibility.jd
+++ b/docs/html-intl/intl/ru/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>Зависимости</h3>
 
 <p>Чтобы воспользоваться этими возможностями в версиях Android, предшествующих 5.0 (уровень API 21), включите в свой проект вспомогательную библиотеку
-Android v7 как <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">зависимость Gradle</a>:</p>
+Android v7 как <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">зависимость Gradle</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/vi/training/material/compatibility.jd b/docs/html-intl/intl/vi/training/material/compatibility.jd
index 65e8131..e19a745 100644
--- a/docs/html-intl/intl/vi/training/material/compatibility.jd
+++ b/docs/html-intl/intl/vi/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>Phụ thuộc</h3>
 
 <p>Để sử dụng những tính năng này trong các phiên bản Android trước 5.0 (API mức 21), hãy thêm
-Thư viện Hỗ trợ v7 của Android vào dự án của bạn như một <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Phần phụ thuộc Gradle</a>:</p>
+Thư viện Hỗ trợ v7 của Android vào dự án của bạn như một <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">Phần phụ thuộc Gradle</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/zh-cn/training/material/compatibility.jd b/docs/html-intl/intl/zh-cn/training/material/compatibility.jd
index aa23d4b..9ba8569 100644
--- a/docs/html-intl/intl/zh-cn/training/material/compatibility.jd
+++ b/docs/html-intl/intl/zh-cn/training/material/compatibility.jd
@@ -123,7 +123,7 @@
 <h3>依赖项</h3>
 
 <p>如果要在 Android 5.0(API 级别 21)之前的 Android 版本中使用这些功能,请将
-Android v7 支持内容库作为 <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle 依赖项</a>包括在您的项目中:</p>
+Android v7 支持内容库作为 <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">Gradle 依赖项</a>包括在您的项目中:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html-intl/intl/zh-tw/training/material/compatibility.jd b/docs/html-intl/intl/zh-tw/training/material/compatibility.jd
index 767788b..7d3cdde 100644
--- a/docs/html-intl/intl/zh-tw/training/material/compatibility.jd
+++ b/docs/html-intl/intl/zh-tw/training/material/compatibility.jd
@@ -122,7 +122,7 @@
 
 <h3>相依性</h3>
 
-<p>如果要在 Android 5.0 (API 級別 21) 以前的版本中使用這些功能,請在您的專案中包含 Android v7 支援程式庫做為 <a href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle 相依性</a>:
+<p>如果要在 Android 5.0 (API 級別 21) 以前的版本中使用這些功能,請在您的專案中包含 Android v7 支援程式庫做為 <a href="{@docRoot}sdk/installing/studio-build.html#dependencies">Gradle 相依性</a>:
 </p>
 
 <pre>
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 4d93c83..2223dbf 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -988,7 +988,7 @@
 on different screens:</p>
 
 <ol>
-  <li>Use {@code wrap_content}, {@code fill_parent}, or {@code dp} units when specifying
+  <li>Use {@code wrap_content}, {@code match_parent}, or {@code dp} units when specifying
 dimensions in an XML layout file</li>
   <li>Do not use hard coded pixel values in your application code</li>
   <li>Do not use {@code AbsoluteLayout} (it's deprecated)</li>
@@ -998,7 +998,7 @@
 <p>The following sections provide more details.</p>
 
 
-<h3 id="use-relative">1. Use wrap_content, fill_parent, or the dp unit for layout dimensions</h3>
+<h3 id="use-relative">1. Use wrap_content, match_parent, or the dp unit for layout dimensions</h3>
 
 <p>When defining the <a
 href="{@docRoot}reference/android/view/ViewGroup.LayoutParams.html#attr_android:layout_width"
@@ -1006,7 +1006,7 @@
 href="{@docRoot}reference/android/view/ViewGroup.LayoutParams.html#attr_android:layout_height"
 >{@code android:layout_height}</a> for
 views in an XML layout file, using <code>"wrap_content"</code>,
-<code>"fill_parent"</code> or <code>dp</code> units guarantees that the view is
+<code>"match_parent"</code> or <code>dp</code> units guarantees that the view is
 given an appropriate size on the current device screen.</p>
 
 <p>For instance, a view with a <code>layout_width="100dp"</code> measures 100 pixels wide on
diff --git a/docs/html/guide/practices/verifying-apps-art.jd b/docs/html/guide/practices/verifying-apps-art.jd
index 8a88222..217c65c 100644
--- a/docs/html/guide/practices/verifying-apps-art.jd
+++ b/docs/html/guide/practices/verifying-apps-art.jd
@@ -63,7 +63,7 @@
 java.lang.System#gc() System.gc()} to prompt garbage collection (GC). This should be
 far less necessary with ART, particularly if you're invoking garbage collection
 to prevent <a
-href="{@docRoot}/tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
+href="{@docRoot}tools/debugging/debugging-memory.html#LogMessages"><code>GC_FOR_ALLOC</code></a>-type
 occurrences or to reduce fragmentation. You can verify which runtime is in use
 by calling {@link java.lang.System#getProperty(java.lang.String)
 System.getProperty("java.vm.version")}. If ART is in use, the property's value
diff --git a/docs/html/guide/topics/manifest/activity-element.jd b/docs/html/guide/topics/manifest/activity-element.jd
index e0f5e3d..f30263e 100644
--- a/docs/html/guide/topics/manifest/activity-element.jd
+++ b/docs/html/guide/topics/manifest/activity-element.jd
@@ -714,7 +714,7 @@
 &lt;activity
     android:name="com.example.app.ChildActivity"
     android:label="@string/title_child_activity"
-    android:parentActivityName="com.example.myfirstapp.MainActivity" >
+    android:parentActivityName="com.example.app.MainActivity" >
     &lt;!-- Parent activity meta-data to support API level 4+ -->
     &lt;meta-data
         android:name="android.support.PARENT_ACTIVITY"
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index 6295e0e..2137929 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -5379,10 +5379,15 @@
       "preview/support.html"
     ]
   },
+  "preview/landing/videos/first": {
+    "title": "",
+    "resources": [
+    "https://www.youtube.com/watch?v=CsulIu3UaUM"
+    ]
+  },
   "preview/landing/more": {
     "title": "",
     "resources": [
-      "https://www.youtube.com/watch?v=CsulIu3UaUM",
       "preview/features/multi-window.html",
       "preview/features/notification-updates.html",
       "preview/features/background-optimization.html",
diff --git a/docs/html/ndk/guides/graphics/getting-started.jd b/docs/html/ndk/guides/graphics/getting-started.jd
index 145e534..0c2d939 100644
--- a/docs/html/ndk/guides/graphics/getting-started.jd
+++ b/docs/html/ndk/guides/graphics/getting-started.jd
@@ -137,7 +137,7 @@
 
 <ol style="1">
 <li>Select your project in the Android Studio <em>Project</em> panel.</li>
-<li>From the <strong>Build</strong> menu, choose <strong>Make Module &lt;module-name&gt; </strong>.</li>
+<li>From the <strong>Build</strong> menu, choose <strong>Make Module &lt;module-name&gt; </strong>; or select <strong> Build APK </strong> to generate APK.</li>
 <li>Resolve any dependency issues, and then compile. As Figure 2 shows, you can select individual projects to compile by choosing them from the configuration pulldown.</li>
 
 <img src="../images/config-pulldown.png"
diff --git a/docs/html/ndk/guides/graphics/validation-layer.jd b/docs/html/ndk/guides/graphics/validation-layer.jd
index beac1c0..1a7d832 100644
--- a/docs/html/ndk/guides/graphics/validation-layer.jd
+++ b/docs/html/ndk/guides/graphics/validation-layer.jd
@@ -6,19 +6,8 @@
       <h2>On this page</h2>
 
       <ol>
+        <li><a href="#ilp">Add Validation Layers to Project</a></li>
         <li><a href="#gls">Getting Layer Source</a></li>
-        <li><a href="#ias">Android Studio Integration</a>
-        <ol>
-            <li><a href="#asbl">Building Layers</a></li>
-            <li><a href="#asil">Installing Layers</a></li>
-        </ol>
-        </li>
-        <li><a href="#cli">Integrating on the Command Line</a>
-            <ol>
-            <li><a href="#clibl">Building Layers</a></li>
-            <li><a href="#cliil">Installing Layers</a></li>
-            </ol>
-        </li>
         <li><a href="#verifying">Verifying Layer Build</a></li>
         <li><a href="#enabling">Enabling Layers</a></li>
         <li><a href="#debug">Enabling the Debug Callback</a></li>
@@ -52,272 +41,94 @@
 <p>
 This page explains how to:
 <ul>
+   <li>Integrate NDK's Layer Binaries.</li>
    <li>Get source code for validation layers.</li>
-   <li>Build the layers.</li>
-   <li>Incorporate the layers into your app.</li>
+   <li>Verifying Layer Build.</li>
+   <li>Enabling Layers in Vulkan Application.</li>
+
 </ul>
 </p>
 
+<h2 id="ilp">Add Validation Layers to Project</h2>
+
+<p>
+  NDK release 12 and higher includes pre-built validation layer binaries. At
+  instance and device creation time, when requested by your application, the
+  Vulkan loader finds them in the APK installed location and loads them.
+</p>
+
+<p>
+  To use the pre-built validation layer binaries, either modify the gradle build
+  configuration of your project or manually add the binaries into the JNI
+  libraries directory of your project.
+</p>
+
+
+<h3 id="vl-gradle">Adding validation layers with Gradle</h3>
+
+<p>
+  You can add the validation layer your project using either Andorid Studio's
+  support for CMake and Ndk-build, or using Studio's experimental plugin for
+  Gradle. In general, you should use the CMake and Ndk-build configuration.
+</p>
+
+
+<p>
+  To add the libraries using Android Studio's support for CMake/Ndk-build,
+  add the following to your project's gradle configuration:
+</p>
+
+<pre class="no-pretty-print">
+sourceSets {
+  main {
+    jniLibs {
+      srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
+    }
+  }
+}</pre>
+
+<p>
+  To add the libraries using Android Studio's experimental plugin for Gradle,
+  add the following to your project's gradle configuration:
+</p>
+
+<pre class="no-pretty-print">
+sources {
+  main {
+    jniLibs {
+      source.srcDir "${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs"
+    }
+  }
+}</pre>
+
+
+<h3 id="vl-jni-lib">Adding validation layers to JNI libraries</h3>
+
+<p>
+  If configuring your project's gradle build file is not working, you can
+  manually add the validation layer binaries to your project's JNI libraries
+  directory by using the following command line options:
+</p>
+
+<pre class="no-pretty-print">
+$ cd ${your-app-project-root}
+$ mkdir -p app/src/main
+$ cp -fr ${your-ndk-dir}/sources/third_party/vulkan/src/build-android/jniLibs app/src/main/
+</pre>
+
+
 <h2 id="gls">Getting Layer Source</h2>
 <p>
-This section explains how to build layers from source.
-If you have precompiled layers, you can skip this section, and instead read about how to
-install your layers using <a href="#asil">Android Studio</a> or from the <a href="cliil">
-command line</a>.
-</p>
-<h3 id="ftn">From the NDK (Recommended)</h3>
-
-<p>
-<a href="{@docRoot}ndk/downloads/index.html">NDK Revision 12</a> and later contains source
-code for Android validation layers that is known-good, and ready to build. This code resides under
-the {@code &lt;ndk-root&gt;/sources/third_party/vulkan/src/build-android/generated/gradle-build}
-directory. This version of the layers should be sufficient for most needs. If so, your next task is
-to <a href="#building">build them</a>. Alternatively, you can pull source code from the
-Khronos Group repository.
-</pre>
-</p>
-
-<h3 id="ftr">From the repository</h3>
-
-<p>
-Although we recommend that you use the source code provided with the NDK, you can also pull more
-recent versions of the source code directly from the
+If your app needs the latest validation layer, you can pull the latest source from the Khronos Group
 <a class="external-link" href="https://github.com/KhronosGroup/Vulkan-LoaderAndValidationLayers">
-GitHub repository</a> belonging to the Khronos Group. To do so, perform the following steps.
+GitHub repository</a> and follow the build instructions there.
 </p>
 
-<ol style="1">
-<li>
-Clone the Vulkan directory by entering the following command in your terminal window:
-
-<pre class="no-pretty-print">
-$ git clone git@github.com:KhronosGroup/Vulkan-LoaderAndValidationLayers.git
-</pre>
-
-<p class="note"><strong>Note: </strong>You must have a private SSH key associated with
-GitHub, or this command fails with a {@code Permission denied (publickey)} message.</p>
-</li>
-
-<li>
-Navigate to the directory containing the layer source code, and
-check out the repo's stable Android branch, called {@code android_layers}:
-
-<pre class="no-pretty-print">
-$ cd Vulkan-LoaderAndValidationLayers
-$ git checkout android_layers
-</pre>
-</li>
-
-<li>
-Begin preparation for building by entering the following commands on the command line:
-<ul>
-   <li>For Linux or OS X:
-   <ul>
-      <li>
-      <pre class="no-pretty-print">
-$ cd build-android
-$ ./android-generate</pre>
-      </li>
-   </ul>
-   </li>
-
-   <li>For Windows:
-   <ul>
-      <li>
-<pre class="no-pretty-print">
-&gt; cd build-android
-&gt; android-generate.bat</pre>
-      </li>
-   </ul>
-   </li>
-</ul>
-</li>
-
-<li>
-Continue by following the build instructions for your platform.
-These instructions are in the {@code BUILD.md} file contained in the local instance of the
-repository you cloned.
-</li>
-</ul>
-
-</ol>
-
-<h3 id="ias">Android Studio Integration</h3>
-<p>
-Android Studio builds the validation layers when it builds the rest of the app.
-This flow makes it easier for you to trace through the layers at runtime. Each layer's
-source code corresponds to a single Gradle project, which you can specify directly in your Android
-Studio app. For example, there is a {@code build.gradle} project for threading, and another
-one for parameter validation.
-</p>
-
-<h4 id="asbl">Building layers</h4>
-
-<p>
-To integrate layers directory into Android Studio application, perform these steps:
-</p>
-<li>
-Add layers to your Android Studio application's project by specifying their corresponding
-Gradle projects in {@code settings.gradle}, which is normally a peer to app directory.
-The following example shows how to do this, based on the assumption that you're
-<a href="#ftn">using the {@code build.gradle} files from the NDK</a>.
-
-<pre>
-// configure your path to the source code generated on your machine
-def layerProjRoot = file('/path/to/ndk-root/.../build-android/generated/gradle-build')
-String[] layers = ['threading',
-                   'parameter_validation',
-                   'object_tracker',
-                   'core_validation',
-                   'device_limits',
-                   'image',
-                   'swapchain',
-                   'unique_objects']
-for (layer in layers) {
-    include ":"+ layer
-    project(":" + layer.toString()).projectDir = new File("${layerProjRoot}/${layer}")
-}
-</pre>
-</li>
-
-Your next step is to provide the built layers to the app by installing them.
-
-<h4 id="asil">Installing layers</h4>
-
-<li>
-To install your layers, add the layer Gradle projects to your application's jniLibs dependencies
-in your {@code build.gradle} module. This module normally resides under the {@code app/} directory.
-The following example shows how to do this:
-
-<pre>
-android.sources {
-    main {
-        jni { ... }
-        jniLibs {
-            dependencies {
-                project ":threading"
-                project ":parameter_validation"
-                project ":object_tracker"
-                project ":core_validation"
-                project ":device_limits"
-                project ":image"
-                project ":swapchain"
-                project ":unique_objects"
-            }
-        }
-    }
-} // android.sources
-</pre>
-</li>
-<li>
-Develop, build, and debug as you usually would. When you build, Android Studio automatically
-builds the layers and copies them into your APK.
-</li>
-<li>
-Debug your application. Android Studio allows you to trace through the layer source code.
-</li>
-<li>
-For best performance, remove the layers before you do your release build.
-</li>
-</ol>
-
-
-<h3 id="cli">From the Command Line</h3>
-
-This section explains how to build and install your layers if your project does not use
-Android Studio.
-
-<h4 id="clibl">Building layers</h4>
-
-<p>
-To build validation layers on Linux or OS X, enter these commands on the command line:
-</p>
-<ul>
-<li>
-Using Gradle:
-<pre class="no-pretty-print">
-$ cd generated/gradle-build
-$ # configure SDK and NDK path in local.properties
-$ gradlew assembleAllDebug
-</pre>
-</li>
-<li>
-Using Android makefiles:
-<pre class="no-pretty-print">
-$ ndk-build</pre>
-</li>
-</ul>
-
-<p>
-To build validation layers on Windows, enter these commands on the command line:
-</p>
-<ul>
-<li>
-Using Gradle:
-<pre class="no-pretty-print">
-&gt; cd generated\gradle-build
-&gt; REM configure SDK and NDK path in local.properties
-&gt; gradlew.bat assembleAllDebug
-</pre>
-</li>
-<li>
-Using Android makefiles:
-<pre class="no-pretty-print">
-&gt; ndk-build.cmd
-</pre>
-</li>
-</ul>
-
-
-
-</p>
-</li>
-</ol>
-
-<h4 id="cliil">Installing layers</h4>
-
-<p>
-After building the layers, you must provide them to your app. To do so, you must first
-create a {@code jniLibs} folder in your app's project directory under
-{@code ./src/main/}, and copy the libs to it. The following example shows how to do this.
-</p>
-
-<pre class="no-pretty-print">
-$ mkdir ./src/main/jniLibs
-</pre>
-
-<p>
-The next step depends on whether you are using Gradle or Android makefiles. If you're using
-Gradle, each built layer resides in its own directory. Consolidate the layers into a single
-directory, as the following example shows:
-</p>
-
-<pre class="no-pretty-print">
-$ cp -r .../build-android/generated/gradle-build/threading/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/parameter_validation/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/object_tracker/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/core_validation/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/device_limits/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/image/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/swapchain/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-$ cp -r .../build-android/generated/gradle-build/unique_objects/build/outputs/native/debug/all/lib/* ./src/main/jniLibs/
-</pre>
-
-If you're using Android makefiles, the built layers reside in {@code lib} folders,
-with one {@code lib} folder under each architecture’s root directory. Consolidate the
-makefiles under the {@code jniLibs} directory as this example shows:
-</p>
-<pre class="no-pretty-print">
-$ cp -r .../build-android/libs/* ./src/main/jniLibs/
-</pre>
-</li>
-</ol>
-
 <h2 id="verifying">Verifying Layer Build</h2>
 
 <p>
-Regardless of whether you build using Gradle or Android makefiles, the build process produces
-a file structure like the following:
+Regardless of whether you build with NDK's prebuilt layers or you build from the latest source code,
+the build process produces final file structure like the following:
 </p>
 
 <pre class="no-pretty-print">
@@ -571,6 +382,7 @@
 
 </pre>
 
+<p>
 Once your app has registered and enabled the debug callback, the system routes debugging
 messages to a callback that you register. An example of such a callback appears below:
 </p>
diff --git a/docs/html/preview/_book.yaml b/docs/html/preview/_book.yaml
index 0d4b81b..ad67249 100644
--- a/docs/html/preview/_book.yaml
+++ b/docs/html/preview/_book.yaml
@@ -220,6 +220,8 @@
       value: TV 录制
     - name: zh-tw-lang
       value: 電視錄製
+  - title: Key Attestation
+    path: /preview/features/key-attestation.html
   - title: Network Security Configuration
     path: /preview/features/security-config.html
     path_attributes:
diff --git a/docs/html/preview/api-overview.jd b/docs/html/preview/api-overview.jd
index d457d5c..f2bc111 100644
--- a/docs/html/preview/api-overview.jd
+++ b/docs/html/preview/api-overview.jd
@@ -37,6 +37,7 @@
         <li><a href="#apk_signature_v2">APK Signature Scheme v2</a></li>
         <li><a href="#scoped_directory_access">Scoped Directory Access</a></li>
         <li><a href="#keyboard_shortcuts_helper">Keyboard Shortcuts Helper</a></li>
+        <li><a href="#custom_pointer_api">Custom Pointer API</a></li>
         <li><a href="#sustained_performance_api">Sustained Performance API</a></li>
         <li><a href="#vr">VR Support</a></li>
         <li><a href="#print_svc">Print Service Enhancements</a></li>
@@ -701,48 +702,37 @@
 For more information, see <a href="{@docRoot}preview/features/direct-boot.html">Direct Boot</a>.</p>
 </p>
 
-
 <h2 id="key_attestation">Key Attestation</h2>
 
-<p>Hardware-backed keystores provide a much safer method to create, store,
-and use cryptographic keys on Android devices. They protect keys from the
-Linux kernel, potential Android vulnerabilities, and extraction
-from rooted devices.</p>
+<p>
+  Android N introduces <em>key attestation</em>, a new security tool that helps
+  you make sure that the key pairs stored within a device's <a class=
+  "external-link" href=
+  "https://source.android.com/security/keystore/"><em>hardware-backed
+  keystore</em></a> properly protect the sensitive information that your app
+  uses. By using this tool, you gain additional confidence that your app
+  interacts with keys that reside in secure hardware, even if the device
+  running your app is rooted. If you use keys from the hardware-backed keystore
+  in your apps, you should use this tool, particularly if you use the keys to
+  verify sensitive information within your app.
+</p>
 
-<p>To make it easier and more secure to use hardware-backed keystores,
-Android N introduces Key Attestation. Apps and off-devices can use Key
-Attestation to strongly determine whether an RSA or EC key pair is
-hardware-backed, what the properties of the key pair are, and what
-  constraints are applied to its usage and validity. </p>
+<p>
+  Key attestation allows you to verify that an RSA or EC key pair has been
+  created and stored in a device’s hardware-backed keystore within the device’s
+  trusted execution environment (TEE). The tool also allows you to use an
+  off-device service, such as your app's back-end server, to determine and
+  strongly verify the uses and validity of the key pair. These features provide
+  an additional level of security that protects the key pair, even if someone
+  roots the device or compromises the security of the Android platform running
+  on the device.
+</p>
 
-<p>Apps and off-device services can request information about a key pair
-through an X.509 attestation certificate which must be signed by a valid
-attestation key. The attestation key is an ECDSA signing key which is
-injected into the device’s hardware-backed keystore at the factory.
-Therefore, an attestation certificate signed by a valid attestation
-key confirms the existence of a hardware-backed keystore, along with
-  details of key pairs in that keystore.</p>
-
-<p>To ensure that the device is using a secure, official Android factory
-image, Key Attestation requires that the device <a
-class="external-link"
-href="https://source.android.com/security/verifiedboot/verified-boot.html#bootloader_requirements">bootloader</a>
-provide the following information to the <a class="external-link"
-href="https://source.android.com/security/trusty/index.html">Trusted
-Execution Environment (TEE)</a>:</p>
-
-<ul>
-<li>The OS version and patch level installed on the device</li>
-<li>The <a href="https://source.android.com/security/verifiedboot/index.html"
-class="external-link" >Verified Boot</a> public key and lock status</li>
-  </ul>
-
-<p>For more information about the hardware-backed keystore feature,
-see the guide for <a href="https://source.android.com/security/keystore/"
-class="external-link">Hardware-backed Keystore</a>.</p>
-
-<p>In addition to Key Attestation, Android N also introduces
-  fingerprint-bound keys that are not revoked on fingerprint enrollment.</p>
+<p>
+  For more information, see the
+  <a href="{@docRoot}preview/features/key-attestation.html">Key Attestation</a>
+  developer documentation.
+</p>
 
 <h2 id="network_security_config">Network Security Config</h2>
 
@@ -854,18 +844,46 @@
 <h2 id="keyboard_shortcuts_helper">Keyboard Shortcuts Helper</h2>
 
 <p>
-In Android N, the user can press "Alt + /" to trigger a <em>Keyboard Shortcuts</em>
-screen that displays all shortcuts available both from the system and from
-the app in focus. These are retrieved automatically from the app’s menu if
-available, but developers can provide their own fine-tuned shortcuts lists
-for the screen. You can do this by overriding the new
-<code>Activity.onProvideKeyboardShortcuts()</code> method, described in the downloadable
-<a href="{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
+  In Android N, the user can press <strong>Meta + /</strong> to trigger a
+  <em>Keyboard Shortcuts</em> screen that displays all shortcuts available both
+  from the system and from the app in focus. The system retrieves these
+  shortcuts automatically from the app’s menu if the shortcuts exist. You can
+  also provide your own fine-tuned shortcuts lists for the screen. You can do
+  this by overriding the new <code>Activity.onProvideKeyboardShortcuts()</code>
+  method, described in the downloadable <a href=
+  "{@docRoot}preview/setup-sdk.html#docs-dl">API Reference</a>.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> The <strong>Meta</strong> key is not present on all
+  keyboards: on a Macintosh keyboard, it is the <strong>Command</strong> key,
+  on the Windows keyboard, it is the <strong>Windows</strong> key, and on the
+  Pixel C and the Chrome OS keyboards, it is the <strong>Search</strong> key.
 </p>
 
 <p>
-To trigger the Keyboard Shortcuts Helper from anywhere in your app,
-call {@code Activity.requestKeyboardShortcutsHelper()} for the relevant activity.
+  To trigger Keyboard Shortcuts Helper from anywhere in your app, call
+  {@code Activity.requestKeyboardShortcutsHelper()} for the relevant activity.
+</p>
+
+<h2 id="custom_pointer_api">
+  Custom Pointer API
+</h2>
+
+<p>
+  Android N introduces the Custom Pointer API, which lets you customize the
+  appearance, visibility, and behavior of the pointer. This capability is
+  especially useful when a user is using a mouse or touchpad to interact with
+  UI objects. The default pointer uses a standard icon. This API also includes
+  advanced functionality such as changing the pointer icon's appearance based
+  on specific mouse or touchpad movements.
+</p>
+
+<p>
+  To set a pointer icon, override the <code>onResolvePointerIcon()</code>
+  method of the <code>View</code> class. This method uses a
+  <code>PointerIcon</code> object to draw the icon that corresponds to a
+  specific motion event.
 </p>
 
 <h2 id="sustained_performance_api">Sustained Performance API</h2>
diff --git a/docs/html/preview/download-ota.jd b/docs/html/preview/download-ota.jd
index 2058501..18f3e8d 100644
--- a/docs/html/preview/download-ota.jd
+++ b/docs/html/preview/download-ota.jd
@@ -203,72 +203,72 @@
   <tr id="bullhead">
     <td>Nexus 5X <br>"bullhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >bullhead-ota-npd35k-b8cfbd80.zip</a><br>
-      MD5: 15fe2eba9b01737374196bdf0a792fe9<br>
-      SHA-1: 5014b2bba77f9e1a680ac3f90729621c85a14283
+      >bullhead-ota-npd56n-dd5c12ee.zip</a><br>
+      MD5: af9a82e9a78925ca9c1c7f5f6fb851ec<br>
+      SHA-1: e4aabd5634b7ebdeffa877cd9e49244c0be326e4
     </td>
   </tr>
 
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-ota-npd35k-078e6fa5.zip</a><br>
-      MD5: e8b12f7721c53af9a450f7058928a5fc<br>
-      SHA-1: b7a9b756f84a1d2e482ff9c16749d65f6e51425a
+      >shamu-ota-npd56n-2818fd62.zip</a><br>
+      MD5: d8df396b187a8667889260e5464bd676<br>
+      SHA-1: c03c8ef8be587a574565855d4faa526254794e03
     </td>
   </tr>
 
   <tr id="angler">
     <td>Nexus 6P <br>"angler"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >angler-ota-npd35k-88457699.zip</a><br>
-      MD5: 3fac09fef759dde26e57cb80b20b6477<br>
-      SHA-1: 27d6caa786577d8a38b2da5bf94b33b4524a1a1c
+      >angler-ota-npd56n-d2f2611c.zip</a><br>
+      MD5: c3c206892d414d4fc7da892ff840eada<br>
+      SHA-1: 2bdc79409ace5e163ef014ae51977d0a71b83df5
     </td>
   </tr>
 
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-ota-npd35k-51dbae76.zip</a><br>
-      MD5: 58312c4a5971818ef5c77a3f446003da<br>
-      SHA-1: aad9005be33d3e2bab480509a6ab74c3c3b9d921
+      >volantis-ota-npd56n-42228a60.zip</a><br>
+      MD5: c80cf483d8b3c014fc7b27f80957a158<br>
+      SHA-1: f437829320f47ea3aa5f8b70ce2f0bb3d30b3f4f
     </td>
   </tr>
 
   <tr id="volantisg">
     <td>Nexus 9G <br>"volantisg"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantisg-ota-npd35k-834f047f.zip</a><br>
-      MD5: 92b7d1fa252f7394e70f957c72d4aac8<br>
-      SHA-1: b6c057c84d90893630e303cbb60530e20ddb8361
+      >volantisg-ota-npd56n-9b4dbaac.zip</a><br>
+      MD5: 9e55ac1650e4f07a662bafa7f082e91c<br>
+      SHA-1: b9982be56c2817d122664869a1fbe9b13e9c72f7
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-ota-npd35k-6ac91298.zip</a><br>
-      MD5: 1461622ad53ea842b2722fa7b49b8172<br>
-      SHA-1: 409c061668ab270774877d7f3eae44fa48d2b931
+      >fugu-ota-npd56n-b305968a.zip</a><br>
+      MD5: dfc980acad6772d8473ccaa9cbbb681a<br>
+      SHA-1: d7bf8192649dea970afda165d181b4eea07abd7d
     </td>
   </tr>
 
   <tr id="ryu">
     <td>Pixel C <br>"ryu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >ryu-ota-npd35k-a0b2347f.zip</a><br>
-      MD5: c60117f3640cc6db12386fd632289c7d<br>
-      SHA-1: 87349c767c69efb4172c90ce1d88cf578c3d28b3
+      >ryu-ota-npd56n-5bf2fd66.zip</a><br>
+      MD5: 1699e4bacfbef16a75ae6cf3f2e3d886<br>
+      SHA-1: e20f3a8e43fcdd6acef21da80894afc8f9474e33
     </td>
   </tr>
 
   <tr id="seed">
     <td>General Mobile 4G (Android One) <br>"seed"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >seed_l8150-ota-npd35k-09897a1d.zip</a><br>
-      MD5: a55cf94f7cce0393ec6c0b35041766b7<br>
-      SHA-1: 6f33742290eb46f2561891f38ca2e754b4e50c6a
+      >seed_l8150-ota-npd56n-a322696c.zip</a><br>
+      MD5: afc0e363ad2fd7418423e189a339a8e9<br>
+      SHA-1: fc4d818878df51894eac29932dd0e9f6511329c6
     </td>
   </tr>
 
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index b5405c7..ad82211 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -302,72 +302,72 @@
   <tr id="bullhead">
     <td>Nexus 5X <br>"bullhead"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >bullhead-npd35k-factory-5ba40535.tgz</a><br>
-      MD5: b6c5d79a21815ee21db41822dcf61e9f<br>
-      SHA-1: 5ba4053577007d15c96472206e3a79bc80ab194c
+      >bullhead-npd56n-factory-996cac57.tgz</a><br>
+      MD5: 5aadba91f60de00d58dc6198ef5cc3ba<br>
+      SHA-1: 996cac575d83bde573315290da8f52cecc4127d2
     </td>
   </tr>
 
   <tr id="shamu">
     <td>Nexus 6 <br>"shamu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >shamu-npd35k-factory-a33bf20c.tgz</a><br>
-      MD5: e1cf9c57cfb11bebe7f1f5bfbf05d7ab<br>
-      SHA-1: a33bf20c719206bcf08d1edd8da6c0ff9d50f69c
+      >shamu-npd56n-factory-7936bf75.tgz</a><br>
+      MD5: b7ed0db569f3bc2d6655fe8d8cea0e13<br>
+      SHA-1: 7936bf75e6bfb771bd14485211a319b246311b96
     </td>
   </tr>
 
   <tr id="angler">
     <td>Nexus 6P <br>"angler"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >angler-npd35k-factory-81c341d5.tgz</a><br>
-      MD5: e93de7949433339856124c3729c15ebb<br>
-      SHA-1: 81c341d57ef2cd139569b055d5d59e9e592a7abd
+      >angler-npd56n-factory-1ce5ccad.tgz</a><br>
+      MD5: f296eccaed4e2526d6435df8cf0e8df1<br>
+      SHA-1: 1ce5ccad8a3eae143e0ecd9c7afbb1be2f1d41cc
     </td>
   </tr>
 
   <tr id="volantis">
     <td>Nexus 9 <br>"volantis"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantis-npd35k-factory-2b50e19d.tgz</a><br>
-      MD5: 565be87ebb2d5937e2abe1a42645864b<br>
-      SHA-1: 2b50e19dae2667b27f911e3c61ed64860caf43e1
+      >volantis-npd56n-factory-8b9f997e.tgz</a><br>
+      MD5: 111c2fe5777dd6aae71fb8ef35dda9d3<br>
+      SHA-1: 8b9f997ea39fdaf505527536bd346948ae1bae30
     </td>
   </tr>
 
   <tr id="volantisg">
     <td>Nexus 9G <br>"volantisg"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >volantisg-npd35k-factory-2e89ebe6.tgz</a><br>
-      MD5: a8464e15c6683fe2afa378a63e205fda<br>
-      SHA-1: 2e89ebe67a46b2f3beb050746c13341cd11fa678
+      >volantisg-npd56n-factory-ef05106a.tgz</a><br>
+      MD5: 3a6f4d47b385966347bd26b7a922cd6e<br>
+      SHA-1: ef05106a9e3becea5673ea67d6c0cc21a2ec09d4
     </td>
   </tr>
 
   <tr id="fugu">
     <td>Nexus Player <br>"fugu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >fugu-npd35k-factory-1de74874.tgz</a><br>
-      MD5: c0dbb7db671f61b2785da5001cedefcb<br>
-      SHA-1: 1de74874f8d83e14d642f13b5a2130fc2aa55873
+      >fugu-npd56n-factory-a51674a1.tgz</a><br>
+      MD5: b75dc745a64848ea24124db8fa9252ed<br>
+      SHA-1: a51674a1303b17fec0405d513f9c0fe9f225780f
     </td>
   </tr>
 
   <tr id="ryu">
     <td>Pixel C <br>"ryu"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >ryu-npd35k-factory-b4eed85d.tgz</a><br>
-      MD5: bdcb6f770e753668b5fadff2a6678e0d<br>
-      SHA-1: b4eed85de0d42c200348a8629084f78e24f72ac2
+      >ryu-npd56n-factory-e36c49b1.tgz</a><br>
+      MD5: 0a2d660b09e19614a5b3573487b88066<br>
+      SHA-1: e36c49b184843cdfe10278aebc04ce50b6d670b6
     </td>
   </tr>
 
   <tr id="seed">
     <td>General Mobile 4G (Android One) <br>"seed"</td>
     <td><a href="#top" onclick="onDownload(this)"
-      >seed_l8150-npd35k-factory-5ab1212b.tgz</a><br>
-      MD5: 7d34a9774fdd6e025d485ce6cfc23c4c<br>
-      SHA-1: 5ab1212bc9417269d391aacf1e672fff24b4ecc5
+      >seed_l8150-npd56n-factory-dd5d4fd2.tgz</a><br>
+      MD5: 3420581b969af777753141dacc7f73b9<br>
+      SHA-1: dd5d4fd203f9c5dad658434c0ff370c411b78835
     </td>
   </tr>
 
diff --git a/docs/html/preview/features/direct-boot.jd b/docs/html/preview/features/direct-boot.jd
index 3d442d0..8351f4b 100644
--- a/docs/html/preview/features/direct-boot.jd
+++ b/docs/html/preview/features/direct-boot.jd
@@ -108,18 +108,25 @@
 
 <h2 id="notification">Getting Notified of User Unlock</h2>
 
-<p>Once the user unlocks the device after restart, your app can switch to
+<p>When the user unlocks the device after restart, your app can switch to
 accessing credential encrypted storage and use regular system services that
 depend on user credentials.</p>
 
 <p>To get notified when the user unlocks the device after a reboot,
 register a {@link android.content.BroadcastReceiver} from a running component
-to listen for the <code>ACTION_USER_UNLOCKED</code> message. Or, you can
-receive the existing {@link android.content.Intent#ACTION_BOOT_COMPLETED
-ACTION_BOOT_COMPLETED} message, which now indicates the device has booted and
-the user has unlocked the device.</p>
+to listen for unlock notification messages. When the user unlocks the device
+after boot:
+</p>
+<ul>
+<li>If your app has foreground processes that need immediate notification,
+listen for the {@code ACTION_USER_UNLOCKED} message.</li>
+<li>If your app only uses background processes that can act on a delayed
+notification, listen for the
+{@link android.content.Intent#ACTION_BOOT_COMPLETED ACTION_BOOT_COMPLETED}
+message.</li>
+</ul>
 
-<p>You can directly query if the user has unlocked the device by calling
+<p>If the user has unlocked the device, you can find out by calling
 <code>UserManager.isUserUnlocked()</code>.</p>
 
 <h2 id="migrating">Migrating Existing Data</h2>
diff --git a/docs/html/preview/features/key-attestation.jd b/docs/html/preview/features/key-attestation.jd
new file mode 100644
index 0000000..98b8340
--- /dev/null
+++ b/docs/html/preview/features/key-attestation.jd
@@ -0,0 +1,845 @@
+page.title=Key Attestation
+page.metaDescription=New support in Android N for verifying security properties of hardware-backed keys.
+page.keywords="android N", "security", "TEE", "hardware-backed", "keystore", "certificate", "key attestation"
+
+@jd:body
+
+<div id="qv-wrapper">
+  <div id="qv">
+    <h2>In this document</h2>
+      <ol>
+        <li><a href="#verifying">Retrieving and Verifying a Hardware-backed Key Pair</a></li>
+        <li><a href="#certificate_schema">Certificate Extension Data Schema</a></li>
+      </ol>
+  </div>
+</div>
+
+<p>
+  Key Attestation gives you more confidence that the keys you use in your app
+  are stored in a device's hardware-backed keystore. The following sections
+  describe how to verify the properties of hardware-backed keys and how to
+  interpret the schema of the attestation certificate's extension data.
+</p>
+
+<h2 id="verifying">
+  Retrieving and Verifying a Hardware-backed Key Pair
+</h2>
+
+<p>
+  During key attestation, you specify the alias of a key pair. The attestation
+  tool, in return, provides a certificate chain, which you can use to verify
+  the properties of that key pair.
+</p>
+
+<p>
+  The root certificate within this chain is signed using an attestation key,
+  which the device manufacturer injects into the device’s hardware-backed
+  keystore at the factory.
+</p>
+
+<p class="note">
+  <strong>Note:</strong> On devices that ship with Android N and Google Play
+  services, the root certificate is issued by Google. You should verify that
+  this root certificate appears within Google’s list of root certificates.
+</p>
+
+<p>
+  To implement key attestation, complete the following steps:
+</p>
+
+<ol>
+  <li>
+    Use a {@link java.security.KeyStore KeyStore} object's
+    {@link java.security.KeyStore#getCertificateChain getCertificateChain()}
+    method to get a reference to the chain of X.509 certificates associated with
+    the hardware-backed keystore.
+  </li>
+
+  <li>
+    <p>
+      Check each certificate’s validity using a
+      {@link java.security.cert.CRL CRL} object's
+      {@link java.security.cert.CRL#isRevoked isRevoked()} method.
+    </p>
+
+    <p class="caution">
+      <strong>Caution:</strong> Although you can complete this process within
+      your app directly, it’s safer to check the certificates’ revocation lists
+      on a separate server that you trust.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Create an <code>Attestation</code> object, passing in the first element of
+      the certificate chain as an argument:</p>
+
+<pre>
+// "certificates" contains the certificate chain associated with a specific key
+// pair in the device's hardware-backed keystore.
+X509Certificate attestationCert = (X509Certificate) certificates[0];
+Attestation hardwareKeyAttestation = new Attestation(attestationCert);
+</pre>
+
+    <p>
+      An attestation object extracts the extension data within this certificate
+      and stores this information in a more accessible format. For more details
+      about the schema of the extension data, see <a href=
+      "#certificate_schema">Certificate Extension Data Schema</a>.
+    </p>
+  </li>
+
+  <li>
+    <p>
+      Use the accessor methods within the <code>Attestation</code> class to
+      retrieve the extension data from the certificate. These methods use the
+      same names and structure hierarchy as in the certificate extension data
+      schema.
+    </p>
+
+    <p>
+      For example, to view the verified boot key for the device’s TEE, use the
+      following method sequence:
+    </p>
+
+<pre>
+// "hardwareKeyAttestation" contains the first element of the attestation
+// certificate chain.
+AuthorizationList teeAuthList = hardwareKeyAttestation.getTeeEnforced();
+RootOfTrust teeRootOfTrust = teeAuthList.getRootOfTrust();
+byte[] teeVerifiedBootKey = teeRootOfTrust.getVerifiedBootKey();
+</pre>
+
+  </li>
+
+  <li>
+    <p>
+      Compare the extension data from the <code>Attestation</code> object with
+      the set of values that you expect the hardware-backed key to contain.
+    </p>
+
+    <p class="caution">
+      <strong>Caution:</strong> Although you can complete this process within
+      your app directly, it’s safer to check the certificate’s extension data
+      on a separate server that you trust.
+    </p>
+  </li>
+</ol>
+
+<h2 id="certificate_schema">
+  Certificate Extension Data Schema
+</h2>
+
+<p>
+  Key attestation verifies the extension data that appears in the first
+  certificate within the chain in a device’s hardware-backed keystore. The
+  certificate stores the information according to the following ASN.1 schema:
+</p>
+
+<pre class="no-pretty-print">
+KeyDescription ::= SEQUENCE {
+    attestationVersion  INTEGER,
+    attestationSecurityLevel  SecurityLevel,
+    keymasterVersion  INTEGER,
+    keymasterSecurityLevel  SecurityLevel,
+    attestationChallenge  OCTET_STRING,
+    <var>reserved  OCTET_STRING</var>,
+    softwareEnforced  AuthorizationList,
+    teeEnforced  AuthorizationList,
+}
+
+SecurityLevel ::= ENUMERATED {
+    Software  (0),
+    TrustedEnvironment  (1),
+}
+
+AuthorizationList ::= SEQUENCE {
+    purpose  [1] EXPLICIT SET OF INTEGER OPTIONAL,
+    algorithm  [2] EXPLICIT INTEGER OPTIONAL,
+    keySize  [3] EXPLICIT INTEGER OPTIONAL,
+    digest  [5] EXPLICIT SET OF INTEGER OPTIONAL,
+    padding  [6] EXPLICIT SET OF INTEGER OPTIONAL,
+    ecCurve  [10] EXPLICIT INTEGER OPTIONAL,
+    rsaPublicExponent  [200] EXPLICIT INTEGER OPTIONAL,
+    activeDateTime  [400] EXPLICIT INTEGER OPTIONAL,
+    originationExpireDateTime  [401] EXPLICIT INTEGER OPTIONAL,
+    usageExpireDateTime  [402] EXPLICIT INTEGER OPTIONAL,
+    noAuthRequired  [503] EXPLICIT NULL OPTIONAL,
+    userAuthType  [504] EXPLICIT INTEGER OPTIONAL,
+    authTimeout  [505] EXPLICIT INTEGER OPTIONAL,
+    allowWhileOnBody  [506] EXPLICIT NULL OPTIONAL,
+    allApplications  [600] EXPLICIT NULL OPTIONAL,
+    applicationId  [601] EXPLICIT OCTET_STRING OPTIONAL,
+    creationDateTime  [701] EXPLICIT INTEGER OPTIONAL,
+    origin  [702] EXPLICIT INTEGER OPTIONAL,
+    rollbackResistant  [703] EXPLICIT NULL OPTIONAL,
+    rootOfTrust  [704] EXPLICIT RootOfTrust OPTIONAL,
+    osVersion  [705] EXPLICIT INTEGER OPTIONAL,
+    osPatchLevel  [706] EXPLICIT INTEGER OPTIONAL,
+    attestationChallenge  [708] EXPLICIT INTEGER OPTIONAL,
+    attestationApplicationId  [709] EXPLICIT OCTET_STRING OPTIONAL,
+}
+
+RootOfTrust ::= SEQUENCE {
+    verifiedBootKey  OCTET_STRING,
+    deviceLocked  BOOLEAN,
+    verifiedBootState  VerifiedBootState,
+}
+
+VerifiedBootState ::= ENUMERATED {
+    Verified  (0),
+    SelfSigned  (1),
+    Unverified  (2),
+    Failed  (3),
+}
+</pre>
+
+<p>
+  The following list presents a description of each element within the schema:
+</p>
+
+<h3 id="certificate_schema_keydescription">
+  KeyDescription
+</h3>
+
+<p>
+  This sequence of values presents general information about the key pair being
+  verified through key attestation and provides easy access to additional
+  details.
+</p>
+
+<dl>
+  <dt>
+    <code>attestationVersion</code>
+  </dt>
+
+  <dd>
+    The version of the key attestation feature. Should be set to 1.
+  </dd>
+
+  <dt>
+    <code>attestationSecurity</code>
+  </dt>
+
+  <dd>
+    <p>
+      The <a href="#certificate_schema_securitylevel">security
+      level</a> of the attestation.
+    </p>
+
+    <p class="note">
+      <strong>Note:</strong> Although it is possible to attest keys that are
+      stored in the Android system&mdash;that is, if the
+      <code>attestationSecurity</code> value is set to Software&mdash;you
+      cannot trust these attestations if the Android system becomes compromised.
+    </p>
+  </dd>
+
+  <dt>
+    <code>keymasterVersion</code>
+  </dt>
+
+  <dd>
+    The version of the Keymaster hardware abstraction layer (HAL). Use 0 to
+    represent version 0.2 or 0.3, 1 to represent version 1.0, and 2 to represent
+    version 2.0.
+  </dd>
+
+  <dt>
+    <code>keymasterSecurity</code>
+  </dt>
+
+  <dd>
+    The <a href="#certificate_schema_securitylevel">security
+    level</a> of the Keymaster implementation.
+  </dd>
+
+  <dt>
+    <code>attestationChallenge</code>
+  </dt>
+
+  <dd>
+    The challenge string associated with a key pair that is verified using key
+    attestation.
+  </dd>
+
+  <dt>
+    <code><var>reserved</var></code>
+  </dt>
+
+  <dd>
+    Only system apps use this value. In all other apps, this value is empty.
+  </dd>
+
+  <dt>
+    <code>softwareEnforced</code>
+  </dt>
+
+  <dd>
+    Optional. The Keymaster <a href=
+    "#certificate_schema_authorizationlist">authorization
+    list</a> that is enforced by the Android system, not by the device’s TEE.
+  </dd>
+
+  <dt>
+    <code>teeEnforced</code>
+  </dt>
+
+  <dd>
+    Optional. The Keymaster <a href=
+    "#certificate_schema_authorizationlist">authorization
+    list</a> that is enforced by the device’s TEE.
+  </dd>
+</dl>
+
+<h3 id="certificate_schema_securitylevel">
+  SecurityLevel
+</h3>
+
+<p>
+  This data structure indicates the extent to which a software feature, such as
+  a key pair, is protected based on its location within the device.
+</p>
+
+<p>
+  Because the data structure is an enumeration, it takes on exactly one of the
+  following values:
+</p>
+
+<dl>
+  <dt>
+    Software
+  </dt>
+
+  <dd>
+    The logic for creating and managing the feature is implemented in the
+    Android system. For the purposes of creating and storing key pairs, this
+    location is less secure than the TEE but is more secure than your app's
+    process space.
+  </dd>
+
+  <dt>
+    TrustedEnvironment
+  </dt>
+
+  <dd>
+    The logic for creating and managing the feature is implemented in secure
+    hardware, such as a TEE. For the purposes of creating and storing key pairs,
+    this location is more secure because secure hardware is highly resistant to
+    remote compromise.
+  </dd>
+</dl>
+
+<h3 id="certificate_schema_authorizationlist">
+  AuthorizationList
+</h3>
+
+<p>
+  This data structure contains the key pair’s properties themselves, as defined
+  in the Keymaster hardware abstraction layer (HAL). You compare these values
+  to the device’s current state or to a set of expected values to verify that a
+  key pair is still valid for use in your app.
+</p>
+
+<p>
+  Each field name corresponds to a similarly-named Keymaster tag. For example,
+  the <code>keySize</code> field in an authorization list corresponds to the
+  <code>KM_TAG_KEY_SIZE</code> Keymaster tag.
+</p>
+
+<p>
+  Each field in the following list is optional:
+</p>
+
+<dl>
+  <dt>
+    <code>purpose</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_purpose">
+    KM_TAG_PURPOSE</a></code> Keymaster tag, which uses a tag ID value of 1.
+  </dd>
+
+  <dt>
+    <code>algorithm</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code><a href=
+      "https://source.android.com/security/keystore/implementer-ref.html#km_tag_algorithm">
+      KM_TAG_ALGORITHM</a></code> Keymaster tag, which uses a tag ID value of
+      2.
+    </p>
+
+    <p>
+      When an <code>AuthorizationList</code> object is associated with key
+      attestation, this value is always <code>KM_ALGORITHM_RSA</code> or
+      <code>KM_ALGORITHM_EC</code>.
+    </p>
+  </dd>
+
+  <dt>
+    <code>keySize</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_key_size">
+    KM_TAG_KEY_SIZE</a></code> Keymaster tag, which uses a tag ID value of 3.
+  </dd>
+
+  <dt>
+    <code>digest</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_digest">
+    KM_TAG_DIGEST</a></code> Keymaster tag, which uses a tag ID value of 5.
+  </dd>
+
+  <dt>
+    <code>padding</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_padding">
+    KM_TAG_PADDING</a></code> Keymaster tag, which uses a tag ID value of 6.
+  </dd>
+
+  <dt>
+    <code>ecCurve</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_EC_CURVE</code> Keymaster tag, which uses
+      a tag ID value of 10.
+    </p>
+
+    <p>
+      The set of parameters used to generate an elliptic curve (EC) key pair,
+      which uses ECDSA for signing and verification, within the Android system
+      keystore.
+    </p>
+  </dd>
+
+  <dt>
+    <code>rsaPublicExponent</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_rsa_public_exponent">
+    KM_TAG_RSA_PUBLIC_EXPONENT</a></code> Keymaster tag, which uses a tag ID
+    value of 200.
+  </dd>
+
+  <dt>
+    <code>activeDateTime</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_active_datetime">
+    KM_TAG_ACTIVE_DATETIME</a></code> Keymaster tag, which uses a tag ID value
+    of 400.
+  </dd>
+
+  <dt>
+    <code>originationExpireDateTime</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_origination_expire_datetime">
+    KM_TAG_ORIGINATION_EXPIRE_DATETIME</a></code> Keymaster tag, which uses a
+    tag ID value of 401.
+  </dd>
+
+  <dt>
+    <code>usageExpireDateTime</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_usage_expire_datetime">
+    KM_TAG_USAGE_EXPIRE_DATETIME</a></code> Keymaster tag, which uses a tag ID
+    value of 402.
+  </dd>
+
+  <dt>
+    <code>noAuthRequired</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code><a href=
+      "https://source.android.com/security/keystore/implementer-ref.html#km_tag_no_auth_required">
+      KM_TAG_NO_AUTH_REQUIRED</a></code> Keymaster tag, which uses a tag ID
+      value of 503.
+    </p>
+
+    <p>
+      When an <code>AuthorizationList</code> object is associated with key
+      attestation, this value is always true.
+    </p>
+  </dd>
+
+  <dt>
+    <code>userAuthType</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_user_auth_type">
+    KM_TAG_USER_AUTH_TYPE</a></code> Keymaster tag, which uses a tag ID value
+    of 504.
+  </dd>
+
+  <dt>
+    <code>authTimeout</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_auth_timeout">
+    KM_TAG_AUTH_TIMEOUT</a></code> Keymaster tag, which uses a tag ID value of
+    505.
+  </dd>
+
+  <dt>
+    <code>allowWhileOnBody</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_ALLOW_WHILE_ON_BODY</code> Keymaster tag,
+      which uses a tag ID value of 506.
+    </p>
+
+    <p>
+      Allows the key to be used after its authentication timeout period if the
+      user is still wearing the device on their body. Note that a secure
+      on-body sensor determines whether the device is being worn on the user’s
+      body.
+    </p>
+
+    <p>
+      When an <code>AuthorizationList</code> object is associated with key
+      attestation, this value is always true.
+    </p>
+  </dd>
+
+  <dt>
+    <code>allApplications</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_ALL_APPLICATIONS</code> Keymaster tag,
+      which uses a tag ID value of 600.
+    </p>
+
+    <p>
+      Indicates whether all apps on a device can access the key pair.
+    </p>
+
+    <p>
+      When an <code>AuthorizationList</code> object is associated with key
+      attestation, this value is always true.
+    </p>
+  </dd>
+
+  <dt>
+    <code>applicationId</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_application_id">
+    KM_TAG_APPLICATION_ID</a></code> Keymaster tag, which uses a tag ID value
+    of 601.
+  </dd>
+
+  <dt>
+    <code>creationDateTime</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_creation_datetime">
+    KM_TAG_CREATION_DATETIME</a></code> Keymaster tag, which uses a tag ID
+    value of 701.
+  </dd>
+
+  <dt>
+    <code>origin</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code><a href=
+      "https://source.android.com/security/keystore/implementer-ref.html#km_tag_origin">
+      KM_TAG_ORIGIN</a></code> Keymaster tag, which uses a tag ID value of 702.
+    </p>
+
+    <p>
+      When an <code>AuthorizationList</code> object is associated with key
+      attestation, this value is usually set to
+      <code>KM_ORIGIN_GENERATED</code>. If the attestation uses Keymaster
+      version 0.2 or 0.3, however, the origin may be set to
+      <code>KM_ORIGIN_UNKNOWN</code> instead.
+    </p>
+  </dd>
+
+  <dt>
+    <code>rollbackResistant</code>
+  </dt>
+
+  <dd>
+    Corresponds to the <code><a href=
+    "https://source.android.com/security/keystore/implementer-ref.html#km_tag_rollback_resistant">
+    KM_TAG_ROLLBACK_RESISTANT</a></code> Keymaster tag, which uses a tag ID
+    value of 703.
+  </dd>
+
+  <dt>
+    <code>rootOfTrust</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code><a href=
+      "https://source.android.com/security/keystore/implementer-ref.html#km_tag_root_of_trust">
+      KM_TAG_ROOT_OF_TRUST</a></code> Keymaster tag, which uses a tag ID value
+      of 704.
+    </p>
+
+    <p>
+      For more details, see the section describing the <code><a href=
+      "#certificate_schema_rootoftrust">RootOfTrust</a></code>
+      data structure.
+    </p>
+  </dd>
+
+  <dt>
+    <code>osVersion</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_OS_VERSION</code> Keymaster tag, which
+      uses a tag ID value of 705.
+    </p>
+
+    <p>
+      The version of the Android operating system associated with the
+      Keymaster, specified as a six-digit integer. For example, version 6.0.1
+      is represented as 060001.
+    </p>
+
+    <p>
+      Only Keymaster version 1.0 or higher includes this value in the
+      authorization list.
+    </p>
+  </dd>
+
+  <dt>
+    <code>osPatchLevel</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_PATCHLEVEL</code> Keymaster tag, which
+      uses a tag ID value of 706.
+    </p>
+
+    <p>
+      The month and year associated with the security patch that is being used
+      within the Keymaster, specified as a six-digit integer. For example, the
+      June 2016 patch is represented as 201606.
+    </p>
+
+    <p>
+      Only Keymaster version 1.0 or higher includes this value in the
+      authorization list.
+    </p>
+  </dd>
+
+  <dt>
+    <code>attestationChallenge</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_ATTESTATION_CHALLENGE</code> Keymaster
+      tag, which uses a tag ID value of 708.
+    </p>
+
+    <p>
+      The challenge string associated with the key pair that is defined in the
+      Keymaster.
+    </p>
+  </dd>
+
+  <dt>
+    <code>attestationApplicationId</code>
+  </dt>
+
+  <dd>
+    <p>
+      Corresponds to the <code>KM_TAG_ATTESTATION_APPLICATION_ID</code>
+      Keymaster tag, which uses a tag ID value of 709.
+    </p>
+
+    <p>
+      The unique ID of the attestation certificate that signed the key pair
+      that is in the Keymaster.
+    </p>
+  </dd>
+</dl>
+
+<h3 id="certificate_schema_rootoftrust">
+  RootOfTrust
+</h3>
+
+<p>
+  This collection of values defines key information about the device’s status.
+</p>
+
+<p>
+  Each field in the following list is required:
+</p>
+
+<dl>
+  <dt>
+    <code>verifiedBootKey</code>
+  </dt>
+
+  <dd>
+    <p>
+      A secure hash of the key that verifies the system image. It is recommended
+      that you use the SHA-256 algorithm for this hash.
+    </p>
+  </dd>
+
+  <dt>
+    <code>deviceLocked</code>
+  </dt>
+
+  <dd>
+    True if the device’s bootloader is locked, which enables Verified Boot
+    checking and prevents an unsigned device image from being flashed onto the
+    device. For more information about this feature, see the <a class=
+    "external-link" href=
+    "https://source.android.com/security/verifiedboot/verified-boot.html">Verifying
+    Boot</a> documentation.
+  </dd>
+
+  <dt>
+    <code>verifiedBootState</code>
+  </dt>
+
+  <dd>
+    The <a href="#certificate_schema_verifiedbootstate">boot
+    state</a> of the device, according to the Verified Boot feature.
+  </dd>
+
+  <dt>
+    <code>osVersion</code>
+  </dt>
+
+  <dd>
+    The current version of the Android operating system on the device,
+    specified as a six-digit integer. For example, version 6.0.1 is represented
+    as 060001.
+  </dd>
+
+  <dt>
+    <code>patchMonthYear</code>
+  </dt>
+
+  <dd>
+    The month and year associated with the security patch that is currently
+    installed on the device, specified as a six-digit integer. For example, the
+    June 2016 patch is represented as 201606.
+  </dd>
+</dl>
+
+<h3 id="certificate_schema_verifiedbootstate">
+  VerifiedBootState
+</h3>
+
+<p>
+  This data structure provides the device’s current boot state, which
+  represents the level of protection provided to the user and to apps after the
+  device finishes booting. For more information about this feature, see the
+  <a class="external-link" href=
+  "https://source.android.com/security/verifiedboot/verified-boot.html#boot_state">
+  Boot State</a> section within the Verifying Boot documentation.
+</p>
+
+<p>
+  This data structure is an enumeration, so it takes on exactly one of the
+  following values:
+</p>
+
+<dl>
+  <dt>
+    Verified
+  </dt>
+
+  <dd>
+    <p>
+      Indicates a full chain of trust, which includes the bootloader, the boot
+      partition, and all verified partitions.
+    </p>
+
+    <p>
+      When the device is in this boot state, the <code>verifiedBootKey</code> is
+      the hash of the device-embedded certificate, which the device manufacturer
+      adds to the device's ROM at the factory.
+    </p>
+  </dd>
+
+  <dt>
+    SelfSigned
+  </dt>
+
+  <dd>
+    <p>
+      Indicates that the device-embedded certificate has verified the device’s
+      boot partition and that the signature is valid.
+    </p>
+
+    <p>
+      When the device is in this boot state, the <code>verifiedBootKey</code> is
+      the hash of a user-installed certificate, which signs a boot partition
+      that the user adds to the device in place of the original,
+      manufacturer-provided boot partition.
+    </p>
+  </dd>
+
+  <dt>
+    Unverified
+  </dt>
+
+  <dd>
+    Indicates that the user can modify the device freely. Therefore, the user is
+    responsible for verifying the device’s integrity.
+  </dd>
+
+  <dt>
+    Failed
+  </dt>
+
+  <dd>
+    Indicates that the device has failed verification. The attestation
+    certificate should never use this value for <code>VerifiedBootState</code>.
+  </dd>
+</dl>
diff --git a/docs/html/preview/features/multi-window.jd b/docs/html/preview/features/multi-window.jd
index a4f389a..ca5bd0d 100644
--- a/docs/html/preview/features/multi-window.jd
+++ b/docs/html/preview/features/multi-window.jd
@@ -471,7 +471,7 @@
   </dd>
 
   <dt>
-    <code>Activity.requestDropPermissions()</code>
+    <code>Activity.requestDragAndDropPermissions()</code>
   </dt>
 
   <dd>
diff --git a/docs/html/preview/index.jd b/docs/html/preview/index.jd
index 918de48..0b21e68 100644
--- a/docs/html/preview/index.jd
+++ b/docs/html/preview/index.jd
@@ -114,7 +114,24 @@
     data-initial-results="3"></div>
 </div></section>
 
-<section class="dac-section dac-gray"><div class="wrap">
+
+<section class="dac-section dac-gray" id="videos"><div class="wrap">
+  <h1 class="dac-section-title">Videos</h1>
+  <div class="dac-section-subtitle">
+    New Android capabilities and the right way to use them in your apps.
+  </div>
+
+  <div class="resource-widget resource-flow-layout col-16"
+    data-query="collection:preview/landing/videos/first,type:youtube+tag:androidn"
+    data-sortOrder="-timestamp"
+    data-cardSizes="6x6"
+    data-items-per-page="6"
+    data-maxResults="15"
+    data-initial-results="3"></div>
+</div></section>
+
+
+<section class="dac-section dac-light" id="resources"><div class="wrap">
   <h1 class="dac-section-title">Resources</h1>
   <div class="dac-section-subtitle">
     Essential information to help you get your apps ready for Android N.
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 3b479e2..58ca1d0 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -76,6 +76,12 @@
 
 <h3 id="docs-dl">Get the N Preview reference documentation</h3>
 
+<p class="note">
+  <strong>Note:</strong> The N Preview (API level 24) reference documentation
+  is now available online at <a href=
+  "{@docRoot}reference/">developer.android.com/reference/</a>.
+</p>
+
 <p>
   Detailed information about the Android N APIs is available in the N Preview
   reference documentation, which you can download from the following table.
@@ -95,7 +101,7 @@
       >n-preview-3-docs.zip</a></td>
     <td width="100%">
       MD5: 19bcfd057a1f9dd01ffbb3d8ff7b8d81<br>
-      SHA-1: 9224bd4445cd7f653c4c294d362ccb195a2101e7 
+      SHA-1: 9224bd4445cd7f653c4c294d362ccb195a2101e7
     </td>
   </tr>
 </table>
diff --git a/docs/html/topic/libraries/support-library/revisions.jd b/docs/html/topic/libraries/support-library/revisions.jd
index 7525760..88b0ca1 100644
--- a/docs/html/topic/libraries/support-library/revisions.jd
+++ b/docs/html/topic/libraries/support-library/revisions.jd
@@ -6,6 +6,124 @@
 <p>This page provides details about the Support Library package releases.</p>
 
 <div class="toggle-content opened">
+  <p id="rev24-0-0">
+    <a href="#" onclick="return toggleContent(this)"><img src=
+    "{@docRoot}assets/images/styles/disclosure_up.png" class=
+    "toggle-content-img" alt="">Android Support Library, revision 24.0.0</a>
+    <em>(June 2016)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <dl>
+      <dt>
+        Changes for <a href=
+        "{@docRoot}tools/support-library/features.html#v4">v4 Support
+        Library</a>:
+      </dt>
+
+      <dd>
+          <ul>
+            <li>Added <code>Fragment.commitNow()</code>
+            for synchronous commit
+            </li>
+
+            <li>Added <code>NotificationCompat.MessagingStyle</code>
+            for multi-party conversations
+            </li>
+
+            <li>Added <code>NotificationManagerCompat.areNotificationsEnabled()</code>
+            and <code>getImportance()</code>
+            </li>
+
+            <li>{@link android.support.v4.media.session.MediaSessionCompat}
+            now mirrors the functionality of {@link
+            android.media.session.MediaSession} and no longer calls {@link
+            android.media.session.MediaSession#setMediaButtonReceiver
+            setMediaButtonReceiver()} automatically
+            </li>
+          </ul>
+          <p class="note">
+            <strong>Note:</strong> <a href=
+            "{@docRoot}reference/android/support/v4/media/MediaBrowserServiceCompat.html"
+            ><code>MediaBrowserServiceCompat</code></a> is compatible with
+            devices running API Level 24 as of Support Library revision 24.0.0.
+            Older versions of <a href=
+            "{@docRoot}reference/android/support/v4/media/MediaBrowserServiceCompat.html"
+            ><code>MediaBrowserServiceCompat</code></a>
+            are <em>not</em> compatible with API Level 24. If your app uses
+            <a href=
+            "{@docRoot}reference/android/support/v4/media/MediaBrowserServiceCompat.html"
+            ><code>MediaBrowserServiceCompat</code></a> and
+            supports devices running API level 24, you must update to Support
+            Library version 24.0.0 or later.
+          </p>
+
+      <dt>
+        Changes for <a href=
+        "{@docRoot}tools/support-library/features.html#v7-appcompat">v7
+        appcompat library</a>:
+      </dt>
+
+      <dd>
+        <ul>
+          <li>Added support for referencing themed {@link
+            android.content.res.ColorStateList} objects from XML
+          </li>
+        </ul>
+      </dd>
+
+      <dt>
+        Changes for <a href=
+        "{@docRoot}tools/support-library/features.html#design">Design Support
+        Library</a>:
+      </dt>
+
+      <dd>
+        <ul>
+          <li>Improvements to {@link android.support.design.widget.AppBarLayout}
+            handling of elevation using {@link
+            android.animation.StateListAnimator}
+          </li>
+        </ul>
+      </dd>
+
+      <dt>
+        Changes for <a href=
+        "{@docRoot}topic/libraries/support-library/features.html#v17-leanback"
+        >v17 Leanback library</a>:
+      </dt>
+
+      <dd>
+        <ul>
+          <li>Added <code>OnboardingFragment</code> to provide first-run welcome
+            and setup flow
+          </li>
+        </ul>
+      </dd>
+
+      <dt>
+        Changes for <a href=
+        "{@docRoot}topic/libraries/support-library/features.html#custom-tabs"
+        >custom tabs</a>:
+      </dt>
+
+      <dd>
+        <ul>
+          <li>Added support for providing a {@link android.widget.RemoteViews}
+            hierarchy for the secondary toolbar</li>
+          <li>Added <code>CustomTabsClient.connectAndInitialize()</code>
+            for one-line warm up</li>
+        </ul>
+      </dd>
+
+    </dl>
+  </div>
+</div>
+
+<!-- end of collapsible section: 24.0.0 -->
+
+
+<div class="toggle-content closed">
   <p id="rev23-4-0">
     <a href="#" onclick="return toggleContent(this)"><img src=
     "{@docRoot}assets/images/styles/disclosure_up.png" class=
@@ -45,10 +163,9 @@
 
       <dd>
         <ul>
-          <li>Added <!-- TODO: Link to method -->
-             <code><a href=
-            "{@docRoot}reference/android/support/v7/app/AppCompatDelegate.html">
-            AppCompatDelegate</a>.setCompatVectorFromResourcesEnabled()</code>
+          <li>Added
+            {@link android.support.v7.app.AppCompatDelegate#setCompatVectorFromResourcesEnabled
+            AppCompatDelegate.setCompatVectorFromResourcesEnabled()}
             method to re-enable usage of vector drawables in {@link
             android.graphics.drawable.DrawableContainer} objects on devices
             running Android 4.4 (API level 19) and lower. See <a href=
@@ -118,8 +235,9 @@
 
       <dd>
         <ul>
-          <li>Fixed a bug where <!-- TODO: Javadoc link -->
-             <code>VectorDrawableCompat</code> does not render correctly in
+          <li>Fixed a bug where {@link
+            android.support.graphics.drawable.VectorDrawableCompat} does
+            not render correctly in
             {@link android.widget.TextView} on API level 23. (<a class=
             "external-link" href=
             "https://code.google.com/p/android/issues/detail?id=206227">Issue
diff --git a/docs/html/training/basics/supporting-devices/languages.jd b/docs/html/training/basics/supporting-devices/languages.jd
index 7d4d474..ba7c016 100644
--- a/docs/html/training/basics/supporting-devices/languages.jd
+++ b/docs/html/training/basics/supporting-devices/languages.jd
@@ -41,7 +41,7 @@
 <p>To add support for more languages, create additional <code>values</code> directories inside
 <code>res/</code> that include a hyphen and the ISO language code at the end of the
 directory name. For example, <code>values-es/</code> is the directory containing simple
-resourcess for the Locales with the language code "es".  Android loads the appropriate resources
+resources for the Locales with the language code "es".  Android loads the appropriate resources
 according to the locale settings of the device at run time. For more information, see
  <a href="{@docRoot}guide/topics/resources/providing-resources.html#AlternativeResources">Providing Alternative Resources</a>.</p>
 
diff --git a/docs/html/training/material/compatibility.jd b/docs/html/training/material/compatibility.jd
index 9ea88b2..8ebe6f6 100644
--- a/docs/html/training/material/compatibility.jd
+++ b/docs/html/training/material/compatibility.jd
@@ -127,7 +127,7 @@
 
 <p>To use these features in versions of Android earlier than 5.0 (API level 21), include the
 Android v7 Support Library in your project as a <a
-href="{@docRoot}/studio/build/index.html#dependencies">Gradle dependency</a>:</p>
+href="{@docRoot}studio/build/index.html#dependencies">Gradle dependency</a>:</p>
 
 <pre>
 dependencies {
diff --git a/docs/html/training/wearables/data-layer/events.jd b/docs/html/training/wearables/data-layer/events.jd
index 9bed9d5..20f219d 100644
--- a/docs/html/training/wearables/data-layer/events.jd
+++ b/docs/html/training/wearables/data-layer/events.jd
@@ -22,21 +22,21 @@
 <h2 id="Wait">Wait for the Status of Data Layer Calls</h2>
 
 <p>You'll notice that calls to the Data Layer API sometimes return a
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>,
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>,
 such as
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>.
-As soon as the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> is created,
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#putDataItem(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.PutDataRequest)"><code>putDataItem()</code></a>.
+As soon as the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> is created,
 the operation is queued in the background. If you do nothing else after this, the operation
 eventually completes silently. However, you'll usually want to do something with the result
 after the operation completes, so the
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
 lets you wait for the result status, either synchronously or asynchronously.
 </p>
 
 <h3 id="async-waiting">Asynchronous calls</h3>
 <p>If your code is running on the main UI thread, do not make blocking calls
 to the Data Layer API. You can run the calls asynchronously by adding a callback method
-to the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object,
+to the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a> object,
 which fires when the operation is completed:</p>
 <pre>
 pendingResult.setResultCallback(new ResultCallback&lt;DataItemResult&gt;() {
@@ -51,12 +51,12 @@
 
 <h3 id="sync-waiting">Synchronous calls</h3>
 <p>If your code is running on a separate handler thread in a background service (which is the case
-in a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>),
+in a <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html"><code>WearableListenerService</code></a>),
 it's fine for the calls to block. In this case, you can call
-<a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a>
-on the <a href="{@docRoot}reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html#await()"><code>await()</code></a>
+on the <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/PendingResult.html"><code>PendingResult</code></a>
 object, which blocks until the request completes and returns a
-<a href="{@docRoot}reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/Result.html"><code>Result</code></a>
 object:
 </p>
 
@@ -79,7 +79,7 @@
 </p>
 <ul>
    <li>Create a service that extends <a href
-="https://developer.android.com/reference/com/google/android/gms/wearable/WearableListenerService.html">
+="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
 {@code WearableListenerService}</a>.</li>
    <li>Create an activity that implements <a
 href="https://developer.android.com/reference/com/google/android/gms/wearable/DataApi.DataListener.html">
@@ -215,7 +215,7 @@
 
 <p>
 An intent filter for the
-<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
 {@code WearableListenerService}</a> example shown in the previous section might look like this:
 
 <pre>
@@ -250,14 +250,14 @@
 or path prefix, you must specify a wildcard or specific host.
 If you do not do so, the system ignores the path you specified.
 </p>
+
 <p>
 For more information on the filter types that Wear supports, see the
 API reference documentation for <a
 href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService">
 {@code WearableListenerService}</a>.
-
-
 </p>
+
 <p>
 For more information on data filters and matching rules, see the API reference
 documentation for the <a
@@ -265,7 +265,6 @@
 manifest element.
 </p>
 
-
 <p>When matching intent filters, there are two important rules to remember:</p>
 <ul>
     <li>If a scheme is not specified for the intent filter, the system ignores
@@ -282,10 +281,10 @@
 implementing one or more of the following interfaces:
 </p>
 <ul>
-  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
+  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>
   DataApi.DataListener</code></a></li>
 
-  <li><a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
+  <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html">
   <code>MessageApi.MessageListener</code></a></li>
 
   <li><a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener.html">{@code CapabilityApi.CapabilityListener}</a></li>
@@ -295,21 +294,21 @@
 <ol>
 <li>Implement the desired interfaces.</li>
 <li>In {@link android.app.Activity#onCreate onCreate()}, create an instance of
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html"><code>GoogleApiClient</code>
 </a>to work with the Data Layer API.</li>
 
 <li>
-In {@link android.app.Activity#onStart onStart()}, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
+In {@link android.app.Activity#onStart onStart()}, call <a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()">
 <code>connect()</code></a> to connect the client to Google Play services.
 </li>
 
 <li>When the connection to Google Play services is established, the system calls
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>. This is where you call
 
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)">
 <code>DataApi.addListener()</code></a>,
 
-<a href="{@docRoot}android/reference/com/google/android/gms/wearable/CapabilityApi.CapabilityListener">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener, android.net.Uri, int)">
 <code>MessageApi.addListener()</code></a>, or
 
 <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#addListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.CapabilityApi.CapabilityListener,%20android.net.Uri,%20int)">
@@ -317,14 +316,16 @@
 interested in listening for data layer events.</li>
 
 <li>In {@link android.app.Activity#onStop onStop()}, unregister any listeners with
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
-<a href="{@docRoot}reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
-<a href="http://developer.android.com/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient,%20com.google.android.gms.wearable.MessageApi.MessageListener)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.DataApi.DataListener)"><code>DataApi.removeListener()</code></a>,
+
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.MessageApi.MessageListener)"><code>MessageApi.removeListener()</code></a>, or
+
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/CapabilityApi.html#removeListener(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.wearable.CapabilityApi.CapabilityListener)">
 {@code CapabilityApi.removeListener()}</a>.</li>
 
 
 <p>An alternative to adding listeners in
-<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"><code>onConnected()</code></a>
 and removing them in
 {@link android.app.Activity#onStop onStop()} is to add a filtered listener in an activity’s {@link android.app.Activity#onResume onResume()} and
 remove it in {@link android.app.Activity#onPause onPause()}, so as to only receive data that is relevant to the
@@ -332,18 +333,18 @@
 
 
 <li>Implement
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html#onDataChanged(com.google.android.gms.wearable.DataEventBuffer)">
 <code>onDataChanged()</code></a>,
   <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/MessageApi.MessageListener.html#onMessageReceived(com.google.android.gms.wearable.MessageEvent)">
   <code>onMessageReceived()</code></a>,
   <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html#onCapabilityChanged(com.google.android.gms.wearable.CapabilityInfo)">
 {@code onCapabilityChanged()}</a>,
-or methods from <a href="http://developer.android.com/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
+or methods from <a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/ChannelApi.ChannelListener.html">
 Channel API listener methods</a>, depending on the interfaces that you implemented.</li>
 </ol>
 
 <p>Here's an example that implements
-<a href="{@docRoot}reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>:</p>
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/DataApi.DataListener.html"><code>DataApi.DataListener</code></a>:</p>
 
 <pre>
 public class MainActivity extends Activity implements
@@ -403,7 +404,7 @@
 <h3>Using Filters with Listener Activities</h3>
 <p>
 Just as you can specify intent filters for manifest-based
-<a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html">
+<a href="https://developers.google.com/android/reference/com/google/android/gms/wearable/WearableListenerService.html">
 <code>WearableListenerService</code></a> objects, you can also use intent filters when registering a
 listener through the Wearable API. The same rules are applicable to both
 API-based listeners manifest-based listeners.
@@ -411,7 +412,7 @@
 
 <p>
 A common pattern is to register a listener with a specific path or path prefix
-in an activity’s{@link android.app.Activity#onResume onResume()} method, and to
+in an activity’s {@link android.app.Activity#onResume onResume()} method, and to
 remove the listener in the activity’s {@link android.app.Activity#onPause onPause()} method.
 Implementing listeners in this fashion allows your application to more selectively receive events,
 improving its design and efficiency.
diff --git a/docs/html/training/wearables/watch-faces/performance.jd b/docs/html/training/wearables/watch-faces/performance.jd
index 4a96545..a83a72b 100644
--- a/docs/html/training/wearables/watch-faces/performance.jd
+++ b/docs/html/training/wearables/watch-faces/performance.jd
@@ -6,30 +6,117 @@
 <div id="tb">
 <h2>This lesson teaches you to</h2>
 <ol>
+  <li><a href="#Basic">Basic Optimization</a></li>
+  <li><a href="#Animations">Best Practices for Animations</a></li>
   <li><a href="#ReduceSize">Reduce the Size of Your Bitmap Assets</a></li>
   <li><a href="#CombineBitmaps">Combine Bitmap Assets</a></li>
   <li><a href="#AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</a></li>
   <li><a href="#OutDrawing">Move Expensive Operations Outside the Drawing Method</a></li>
-  <li><a href="#SavePower">Follow Best Practices to Save Power</a></li>
 </ol>
 <h2>You should also read</h2>
 <ul>
   <li><a href="{@docRoot}design/wear/watchfaces.html">Watch Faces for Android Wear</a></li>
   <li><a href="http://android-developers.blogspot.com/2014/12/making-performant-watch-face.html">
 Making a performant watch face</a></li>
+  <li><a href="http://android-developers.blogspot.com/2016/04/deprecation-of-bindlistener.html">
+Deprecation of BIND_LISTENER with Android Wear APIs</a></li>
 </ul>
 </div>
 </div>
 
-<p>In addition to accommodating notification cards and system indicators, you need to ensure that
-the animations in your watch face run smoothly and that your service does not perform unnecessary
-computations. Watch faces in Android Wear run continuously on the device, so it is critical
-that your watch face uses power efficiently.</p>
+<p>This lesson has tips for conserving power and improving performance.
+A watch face runs continuously, so it must use power
+efficiently. </p>
 
-<p>This lesson provides some tips to speed up your animations and to measure and conserve
-power on the device.</p>
+<p>Services must not perform unnecessary computations.
+Watch faces with animations must run smoothly while accommodating
+notification cards and system indicators.</p>
 
+<h2 id="Basic">Basic Optimization</h2>
 
+<p>This section contains best practices for improving efficiency during
+periods when a watch face is inactive.</p>
+
+<h3>Use callbacks in WatchFaceService.Engine</h3>
+
+<p>Ensure that your watch face performs
+computations only when active; use callbacks
+in <a href="{@docRoot}reference/android/support/wearable/watchface/
+WatchFaceService.Engine.html">{@code WatchFaceService.Engine}</a>.
+Preferably, use the following methods of that class to determine if
+the watch face is visible:</p>
+
+<ul>
+  <li>{@code onVisibilityChanged(boolean)}</li>
+  <li>{@code isVisible()}</li>
+</ul>
+
+<p>Alternatively, use the following methods of the same class
+(<a href="{@docRoot}reference/android/support/wearable/watchface/
+WatchFaceService.Engine.html">{@code WatchFaceService.Engine}</a>):</p>
+
+<ul>
+  <li>{@code onCreate()}</li>
+  <li>{@code onDestroy()}</li>
+</ul>
+
+<h3>Use listeners registered with the DataApi interface</h3>
+
+<p>To listen for events, use live listeners that are registered
+with <a href="https://developers.google.com/android/reference/com/google/
+android/gms/wearable/DataApi.html#addListener
+(com.google.android.gms.common.api.GoogleApiClient, com.
+google.android.gms.wearable.DataApi.DataListener)">{@code DataApi.addListener}</a>.
+For an example, see <a href="{@docRoot}training/wearables/data-layer/
+data-items.html#ListenEvents">Syncing Data Items</a>.</p>
+
+<p>Do not use <a href="https://developers.google.com/
+android/reference/com/google/android/gms/wearable/
+WearableListenerService">{@code WearableListenerService}</a> to listen for
+events, because it is
+called whether or not a watch face is active. For more information, see
+<a href="http://android-developers.blogspot.com/2016/04/
+deprecation-of-bindlistener.html">Deprecation of BIND_LISTENER
+with Android Wear APIs</a>.</p>
+
+<p>Do not register a broadcast receiver in the Android manifest file
+to get system events such as time zone changes, battery events, etc., because
+the <a href="{@docRoot}reference/android/content/BroadcastReceiver.html">{@code BroadcastReceiver}</a>
+is called whether or not a watch face is active. However, you can use the
+<a href="{@docRoot}reference/android/content/Context.html#registerReceiver(android.
+content.BroadcastReceiver, android.content.IntentFilter)">{@code registerReceiver}</a> method
+of the {@code Context} class to register a receiver.</p>
+
+<h3>Monitor power consumption</h3>
+
+<p>The <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">
+Android Wear companion app</a> enables developers and users to see how much battery
+is consumed by different processes
+on the wearable device (under <strong>Settings</strong> > <strong>Watch
+battery</strong>).</p>
+
+<p>For information about features introduced in Android 5.0 that help you improve battery life,
+see <a href="{@docRoot}about/versions/android-5.0.html#Power">Project Volta</a>.</p>
+
+<h2 id="Animations">Best Practices for Animations</h2>
+
+<p>The best practices in this section help to reduce the power consumption of animations.</p>
+
+<h3>Reduce the frame rate of animations</h3>
+
+<p>Animations are often computationally expensive and consume a significant amount of power. Most
+animations look fluid at 30 frames per second, so you should avoid running your animations
+at a higher frame rate.</p>
+
+<h3>Let the CPU sleep between animations</h3>
+
+<p>Animations and small changes to the contents of the watch face wake up the CPU. Your watch
+face should let the CPU sleep in between animations. For example, you can use short bursts of
+animation every second in interactive mode and then let the CPU sleep until the next second.
+Letting the CPU sleep often, even briefly, can significantly reduce power consumption.</p>
+
+<p>To maximize battery life, use animations sparingly. Even a blinking colon wakes up the CPU with
+every blink and hurts battery life.</p>
 
 <h2 id="ReduceSize">Reduce the Size of Your Bitmap Assets</h2>
 
@@ -68,16 +155,12 @@
 <p>Reducing the size of your bitmap assets as described in this section not only improves
 the performance of your animations, but it also saves power.</p>
 
-
-
 <h2 id="CombineBitmaps">Combine Bitmap Assets</h2>
 
 <p>If you have bitmaps that are often drawn together, consider combining them into the same
 graphic asset. You can often combine the background image in interactive mode with the tick
 marks to avoid drawing two full-screen bitmaps every time the system redraws the watch face.</p>
 
-
-
 <h2 id="AntiAlias">Disable Anti-Aliasing when Drawing Scaled Bitmaps</h2>
 
 <p>When you draw a scaled bitmap on the {@link android.graphics.Canvas} object using the {@link
@@ -139,35 +222,3 @@
 consistent across invocations. For more information, see
 <a href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a>.</p>
 
-
-
-<h2 id="SavePower">Follow Best Practices to Save Power</h2>
-
-<p>In addition to the techniques described in the previous sections, follow the best
-practices in this section to reduce the power consumption of your watch face.</p>
-
-<h3>Reduce the frame rate of animations</h3>
-
-<p>Animations are often computationally expensive and consume a significant amount of power. Most
-animations look fluid at 30 frames per second, so you should avoid running your animations
-at a higher frame rate.</p>
-
-<h3>Let the CPU sleep</h3>
-
-<p>Animations and small changes to the contents of the watch face wake up the CPU. Your watch
-face should let the CPU sleep in between animations. For example, you can use short bursts of
-animation every second in interactive mode and then let the CPU sleep until the next second.
-Letting the CPU sleep often, even briefly, can significantly reduce power consumption.</p>
-
-<p>To maximize battery life, use animations sparingly. Even a blinking colon wakes up the CPU with
-every blink and hurts battery life.</p>
-
-<h3>Monitor power consumption</h3>
-
-<p>The <a href="https://play.google.com/store/apps/details?id=com.google.android.wearable.app&hl=en">
-Android Wear companion app</a> lets developers and users see how much battery different processes
-on the wearable device are consuming under <strong>Settings</strong> > <strong>Watch
-battery</strong>.</p>
-
-<p>For more information about new features in Android 5.0 that help you improve battery life,
-see <a href="{@docRoot}about/versions/android-5.0.html#Power">Project Volta</a>.</p>
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 6762bea..6bb93ae 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -46,6 +46,7 @@
 import android.util.Log;
 import android.util.LongArray;
 import android.util.PathParser;
+import android.util.Property;
 import android.util.TimeUtils;
 import android.view.Choreographer;
 import android.view.DisplayListCanvas;
@@ -157,7 +158,7 @@
     private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
 
     /** Local, mutable animator set. */
-    private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorUI(this);
+    private VectorDrawableAnimator mAnimatorSet;
 
     /**
      * The resources against which this drawable was created. Used to attempt
@@ -182,6 +183,7 @@
 
     private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) {
         mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res);
+        mAnimatorSet = new VectorDrawableAnimatorRT(this);
         mRes = res;
     }
 
@@ -390,9 +392,12 @@
                             R.styleable.AnimatedVectorDrawableTarget_animation, 0);
                     if (animResId != 0) {
                         if (theme != null) {
-                            final Animator objectAnimator = AnimatorInflater.loadAnimator(
+                            // The animator here could be ObjectAnimator or AnimatorSet.
+                            final Animator animator = AnimatorInflater.loadAnimator(
                                     res, theme, animResId, pathErrorScale);
-                            state.addTargetAnimator(target, objectAnimator);
+                            updateAnimatorProperty(animator, target, state.mVectorDrawable,
+                                    state.mShouldIgnoreInvalidAnim);
+                            state.addTargetAnimator(target, animator);
                         } else {
                             // The animation may be theme-dependent. As a
                             // workaround until Animator has full support for
@@ -414,6 +419,55 @@
         mRes = state.mPendingAnims == null ? null : res;
     }
 
+    private static void updateAnimatorProperty(Animator animator, String targetName,
+            VectorDrawable vectorDrawable, boolean ignoreInvalidAnim) {
+        if (animator instanceof ObjectAnimator) {
+            // Change the property of the Animator from using reflection based on the property
+            // name to a Property object that wraps the setter and getter for modifying that
+            // specific property for a given object. By replacing the reflection with a direct call,
+            // we can largely reduce the time it takes for a animator to modify a VD property.
+            PropertyValuesHolder[] holders = ((ObjectAnimator) animator).getValues();
+            for (int i = 0; i < holders.length; i++) {
+                PropertyValuesHolder pvh = holders[i];
+                String propertyName = pvh.getPropertyName();
+                Object targetNameObj = vectorDrawable.getTargetByName(targetName);
+                Property property = null;
+                if (targetNameObj instanceof VectorDrawable.VObject) {
+                    property = ((VectorDrawable.VObject) targetNameObj).getProperty(propertyName);
+                } else if (targetNameObj instanceof VectorDrawable.VectorDrawableState) {
+                    property = ((VectorDrawable.VectorDrawableState) targetNameObj)
+                            .getProperty(propertyName);
+                }
+                if (property != null) {
+                    if (containsSameValueType(pvh, property)) {
+                        pvh.setProperty(property);
+                    } else if (!ignoreInvalidAnim) {
+                        throw new RuntimeException("Wrong valueType for Property: " + propertyName
+                                + ".  Expected type: " + property.getType().toString() + ". Actual "
+                                + "type defined in resources: " + pvh.getValueType().toString());
+
+                    }
+                }
+            }
+        } else if (animator instanceof AnimatorSet) {
+            for (Animator anim : ((AnimatorSet) animator).getChildAnimations()) {
+                updateAnimatorProperty(anim, targetName, vectorDrawable, ignoreInvalidAnim);
+            }
+        }
+    }
+
+    private static boolean containsSameValueType(PropertyValuesHolder holder, Property property) {
+        Class type1 = holder.getValueType();
+        Class type2 = property.getType();
+        if (type1 == float.class || type1 == Float.class) {
+            return type2 == float.class || type2 == Float.class;
+        } else if (type1 == int.class || type1 == Integer.class) {
+            return type2 == int.class || type2 == Integer.class;
+        } else {
+            return type1 == type2;
+        }
+    }
+
     /**
      * Force to animate on UI thread.
      * @hide
@@ -462,6 +516,8 @@
         @Config int mChangingConfigurations;
         VectorDrawable mVectorDrawable;
 
+        private final boolean mShouldIgnoreInvalidAnim;
+
         /** Animators that require a theme before inflation. */
         ArrayList<PendingAnimator> mPendingAnims;
 
@@ -473,6 +529,7 @@
 
         public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy,
                 Callback owner, Resources res) {
+            mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
             if (copy != null) {
                 mChangingConfigurations = copy.mChangingConfigurations;
 
@@ -616,8 +673,10 @@
 
                 for (int i = 0, count = pendingAnims.size(); i < count; i++) {
                     final PendingAnimator pendingAnimator = pendingAnims.get(i);
-                    final Animator objectAnimator = pendingAnimator.newInstance(res, t);
-                    addTargetAnimator(pendingAnimator.target, objectAnimator);
+                    final Animator animator = pendingAnimator.newInstance(res, t);
+                    updateAnimatorProperty(animator, pendingAnimator.target, mVectorDrawable,
+                            mShouldIgnoreInvalidAnim);
+                    addTargetAnimator(pendingAnimator.target, animator);
                 }
             }
         }
@@ -982,6 +1041,9 @@
         private static final int REVERSE_ANIMATION = 2;
         private static final int RESET_ANIMATION = 3;
         private static final int END_ANIMATION = 4;
+
+        // If the duration of an animation is more than 300 frames, we cap the sample size to 300.
+        private static final int MAX_SAMPLE_POINTS = 300;
         private AnimatorListener mListener = null;
         private final LongArray mStartDelays = new LongArray();
         private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -992,14 +1054,12 @@
         private boolean mInitialized = false;
         private boolean mIsReversible = false;
         private boolean mIsInfinite = false;
-        // This needs to be set before parsing starts.
-        private boolean mShouldIgnoreInvalidAnim;
         // TODO: Consider using NativeAllocationRegistery to track native allocation
         private final VirtualRefBasePtr mSetRefBasePtr;
         private WeakReference<RenderNode> mLastSeenTarget = null;
         private int mLastListenerId = 0;
         private final IntArray mPendingAnimationActions = new IntArray();
-        private final Drawable mDrawable;
+        private final AnimatedVectorDrawable mDrawable;
 
         VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
             mDrawable = drawable;
@@ -1016,8 +1076,10 @@
                 throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " +
                         "re-initialized");
             }
-            mShouldIgnoreInvalidAnim = shouldIgnoreInvalidAnimation();
             parseAnimatorSet(set, 0);
+            long vectorDrawableTreePtr = mDrawable.mAnimatedVectorState.mVectorDrawable
+                    .getNativeTree();
+            nSetVectorDrawableTarget(mSetPtr, vectorDrawableTreePtr);
             mInitialized = true;
             mIsInfinite = set.getTotalDuration() == Animator.DURATION_INFINITE;
 
@@ -1077,7 +1139,7 @@
                     }  else if (target instanceof VectorDrawable.VFullPath) {
                         createRTAnimatorForFullPath(animator, (VectorDrawable.VFullPath) target,
                                 startTime);
-                    } else if (!mShouldIgnoreInvalidAnim) {
+                    } else if (!mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
                         throw new IllegalArgumentException("ClipPath only supports PathData " +
                                 "property");
                     }
@@ -1086,7 +1148,7 @@
             } else if (target instanceof VectorDrawable.VectorDrawableState) {
                 createRTAnimatorForRootGroup(values, animator,
                         (VectorDrawable.VectorDrawableState) target, startTime);
-            } else if (!mShouldIgnoreInvalidAnim) {
+            } else if (!mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
                 // Should never get here
                 throw new UnsupportedOperationException("Target should be either VGroup, VPath, " +
                         "or ConstantState, " + target == null ? "Null target" : target.getClass() +
@@ -1121,8 +1183,8 @@
                 long propertyPtr = nCreateGroupPropertyHolder(nativePtr, propertyId,
                         (Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
                 if (mTmpValues.dataSource != null) {
-                    float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator
-                            .getDuration());
+                    float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource,
+                            animator.getDuration());
                     nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
                 }
                 createNativeChildAnimator(propertyPtr, startTime, animator);
@@ -1149,7 +1211,7 @@
             long nativePtr = target.getNativePtr();
             if (mTmpValues.type == Float.class || mTmpValues.type == float.class) {
                 if (propertyId < 0) {
-                    if (mShouldIgnoreInvalidAnim) {
+                    if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
                         return;
                     } else {
                         throw new IllegalArgumentException("Property: " + mTmpValues.propertyName
@@ -1158,12 +1220,24 @@
                 }
                 propertyPtr = nCreatePathPropertyHolder(nativePtr, propertyId,
                         (Float) mTmpValues.startValue, (Float) mTmpValues.endValue);
+                if (mTmpValues.dataSource != null) {
+                    // Pass keyframe data to native, if any.
+                    float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource,
+                            animator.getDuration());
+                    nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
+                }
 
             } else if (mTmpValues.type == Integer.class || mTmpValues.type == int.class) {
                 propertyPtr = nCreatePathColorPropertyHolder(nativePtr, propertyId,
                         (Integer) mTmpValues.startValue, (Integer) mTmpValues.endValue);
+                if (mTmpValues.dataSource != null) {
+                    // Pass keyframe data to native, if any.
+                    int[] dataPoints = createIntDataPoints(mTmpValues.dataSource,
+                            animator.getDuration());
+                    nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
+                }
             } else {
-                if (mShouldIgnoreInvalidAnim) {
+                if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
                     return;
                 } else {
                     throw new UnsupportedOperationException("Unsupported type: " +
@@ -1171,45 +1245,63 @@
                             "supported for Paths.");
                 }
             }
-            if (mTmpValues.dataSource != null) {
-                float[] dataPoints = createDataPoints(mTmpValues.dataSource, animator
-                        .getDuration());
-                nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
-            }
             createNativeChildAnimator(propertyPtr, startTime, animator);
         }
 
         private void createRTAnimatorForRootGroup(PropertyValuesHolder[] values,
                 ObjectAnimator animator, VectorDrawable.VectorDrawableState target,
                 long startTime) {
-                long nativePtr = target.getNativeRenderer();
-                if (!animator.getPropertyName().equals("alpha")) {
-                    if (mShouldIgnoreInvalidAnim) {
-                        return;
-                    } else {
-                        throw new UnsupportedOperationException("Only alpha is supported for root "
-                                + "group");
-                    }
+            long nativePtr = target.getNativeRenderer();
+            if (!animator.getPropertyName().equals("alpha")) {
+                if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
+                    return;
+                } else {
+                    throw new UnsupportedOperationException("Only alpha is supported for root "
+                            + "group");
                 }
-                Float startValue = null;
-                Float endValue = null;
-                for (int i = 0; i < values.length; i++) {
-                    values[i].getPropertyValues(mTmpValues);
-                    if (mTmpValues.propertyName.equals("alpha")) {
-                        startValue = (Float) mTmpValues.startValue;
-                        endValue = (Float) mTmpValues.endValue;
-                        break;
-                    }
+            }
+            Float startValue = null;
+            Float endValue = null;
+            for (int i = 0; i < values.length; i++) {
+                values[i].getPropertyValues(mTmpValues);
+                if (mTmpValues.propertyName.equals("alpha")) {
+                    startValue = (Float) mTmpValues.startValue;
+                    endValue = (Float) mTmpValues.endValue;
+                    break;
                 }
-                if (startValue == null && endValue == null) {
-                    if (mShouldIgnoreInvalidAnim) {
-                        return;
-                    } else {
-                        throw new UnsupportedOperationException("No alpha values are specified");
-                    }
+            }
+            if (startValue == null && endValue == null) {
+                if (mDrawable.mAnimatedVectorState.mShouldIgnoreInvalidAnim) {
+                    return;
+                } else {
+                    throw new UnsupportedOperationException("No alpha values are specified");
                 }
-                long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue);
-                createNativeChildAnimator(propertyPtr, startTime, animator);
+            }
+            long propertyPtr = nCreateRootAlphaPropertyHolder(nativePtr, startValue, endValue);
+            if (mTmpValues.dataSource != null) {
+                // Pass keyframe data to native, if any.
+                float[] dataPoints = createFloatDataPoints(mTmpValues.dataSource,
+                        animator.getDuration());
+                nSetPropertyHolderData(propertyPtr, dataPoints, dataPoints.length);
+            }
+            createNativeChildAnimator(propertyPtr, startTime, animator);
+        }
+
+        /**
+         * Calculate the amount of frames an animation will run based on duration.
+         */
+        private static int getFrameCount(long duration) {
+            long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
+            int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
+            int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
+            // We need 2 frames of data minimum.
+            numAnimFrames = Math.max(2, numAnimFrames);
+            if (numAnimFrames > MAX_SAMPLE_POINTS) {
+                Log.w("AnimatedVectorDrawable", "Duration for the animation is too long :" +
+                        duration + ", the animation will subsample the keyframe or path data.");
+                numAnimFrames = MAX_SAMPLE_POINTS;
+            }
+            return numAnimFrames;
         }
 
         // These are the data points that define the value of the animating properties.
@@ -1217,11 +1309,9 @@
         // a point on the path corresponds to the values of translateX and translateY.
         // TODO: (Optimization) We should pass the path down in native and chop it into segments
         // in native.
-        private static float[] createDataPoints(
+        private static float[] createFloatDataPoints(
                 PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) {
-            long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos();
-            int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS);
-            int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs);
+            int numAnimFrames = getFrameCount(duration);
             float values[] = new float[numAnimFrames];
             float lastFrame = numAnimFrames - 1;
             for (int i = 0; i < numAnimFrames; i++) {
@@ -1231,6 +1321,18 @@
             return values;
         }
 
+        private static int[] createIntDataPoints(
+                PropertyValuesHolder.PropertyValues.DataSource dataSource, long duration) {
+            int numAnimFrames = getFrameCount(duration);
+            int values[] = new int[numAnimFrames];
+            float lastFrame = numAnimFrames - 1;
+            for (int i = 0; i < numAnimFrames; i++) {
+                float fraction = i / lastFrame;
+                values[i] = (Integer) dataSource.getValueAtFraction(fraction);
+            }
+            return values;
+        }
+
         private void createNativeChildAnimator(long propertyPtr, long extraDelay,
                                                ObjectAnimator animator) {
             long duration = animator.getDuration();
@@ -1254,16 +1356,19 @@
          * to the last seen RenderNode target and start right away.
          */
         protected void recordLastSeenTarget(DisplayListCanvas canvas) {
-            mLastSeenTarget = new WeakReference<RenderNode>(
-                    RenderNodeAnimatorSetHelper.getTarget(canvas));
-            if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
-                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                    Log.d(LOGTAG, "Target is set in the next frame");
+            final RenderNode node = RenderNodeAnimatorSetHelper.getTarget(canvas);
+            mLastSeenTarget = new WeakReference<RenderNode>(node);
+            // Add the animator to the list of animators on every draw
+            if (mInitialized || mPendingAnimationActions.size() > 0) {
+                if (useTarget(node)) {
+                    if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                        Log.d(LOGTAG, "Target is set in the next frame");
+                    }
+                    for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+                        handlePendingAction(mPendingAnimationActions.get(i));
+                    }
+                    mPendingAnimationActions.clear();
                 }
-                for (int i = 0; i < mPendingAnimationActions.size(); i++) {
-                    handlePendingAction(mPendingAnimationActions.get(i));
-                }
-                mPendingAnimationActions.clear();
             }
         }
 
@@ -1285,10 +1390,15 @@
         private boolean useLastSeenTarget() {
             if (mLastSeenTarget != null) {
                 final RenderNode target = mLastSeenTarget.get();
-                if (target != null && target.isAttached()) {
-                    target.addAnimator(this);
-                    return true;
-                }
+                return useTarget(target);
+            }
+            return false;
+        }
+
+        private boolean useTarget(RenderNode target) {
+            if (target != null && target.isAttached()) {
+                target.registerVectorDrawableAnimator(this);
+                return true;
             }
             return false;
         }
@@ -1483,6 +1593,7 @@
     }
 
     private static native long nCreateAnimatorSet();
+    private static native void nSetVectorDrawableTarget(long animatorPtr, long vectorDrawablePtr);
     private static native void nAddAnimator(long setPtr, long propertyValuesHolder,
              long nativeInterpolator, long startDelay, long duration, int repeatCount);
 
@@ -1498,6 +1609,7 @@
     private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
             float endValue);
     private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
+    private static native void nSetPropertyHolderData(long nativePtr, int[] data, int length);
     private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
     private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
     private static native void nEnd(long animatorSetPtr);
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index f5592fa..a8c8737 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -34,9 +34,12 @@
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.FloatProperty;
+import android.util.IntProperty;
 import android.util.LayoutDirection;
 import android.util.Log;
 import android.util.PathParser;
+import android.util.Property;
 import android.util.Xml;
 
 import com.android.internal.R;
@@ -758,6 +761,13 @@
         return mVectorState.mAutoMirrored;
     }
 
+    /**
+     * @hide
+     */
+    public long getNativeTree() {
+        return mVectorState.getNativeRenderer();
+    }
+
     static class VectorDrawableState extends ConstantState {
         // Variables below need to be copied (deep copy if applicable) for mutation.
         int[] mThemeAttrs;
@@ -790,6 +800,26 @@
         int mLastSWCachePixelCount = 0;
         int mLastHWCachePixelCount = 0;
 
+        final static Property<VectorDrawableState, Float> ALPHA =
+                new FloatProperty<VectorDrawableState>("alpha") {
+                    @Override
+                    public void setValue(VectorDrawableState state, float value) {
+                        state.setAlpha(value);
+                    }
+
+                    @Override
+                    public Float get(VectorDrawableState state) {
+                        return state.getAlpha();
+                    }
+                };
+
+        Property getProperty(String propertyName) {
+            if (ALPHA.getName().equals(propertyName)) {
+                return ALPHA;
+            }
+            return null;
+        }
+
         // This tracks the total native allocation for all the nodes.
         private int mAllocationOfAllNodes = 0;
 
@@ -967,7 +997,7 @@
     }
 
     static class VGroup extends VObject {
-        private static final int ROTATE_INDEX = 0;
+        private static final int ROTATION_INDEX = 0;
         private static final int PIVOT_X_INDEX = 1;
         private static final int PIVOT_Y_INDEX = 2;
         private static final int SCALE_X_INDEX = 3;
@@ -978,7 +1008,7 @@
 
         private static final int NATIVE_ALLOCATION_SIZE = 100;
 
-        private static final HashMap<String, Integer> sPropertyMap =
+        private static final HashMap<String, Integer> sPropertyIndexMap =
                 new HashMap<String, Integer>() {
                     {
                         put("translateX", TRANSLATE_X_INDEX);
@@ -987,19 +1017,123 @@
                         put("scaleY", SCALE_Y_INDEX);
                         put("pivotX", PIVOT_X_INDEX);
                         put("pivotY", PIVOT_Y_INDEX);
-                        put("rotation", ROTATE_INDEX);
+                        put("rotation", ROTATION_INDEX);
                     }
                 };
 
         static int getPropertyIndex(String propertyName) {
-            if (sPropertyMap.containsKey(propertyName)) {
-                return sPropertyMap.get(propertyName);
+            if (sPropertyIndexMap.containsKey(propertyName)) {
+                return sPropertyIndexMap.get(propertyName);
             } else {
                 // property not found
                 return -1;
             }
         }
 
+        // Below are the Properties that wrap the setters to avoid reflection overhead in animations
+        private static final Property<VGroup, Float> TRANSLATE_X =
+                new FloatProperty<VGroup> ("translateX") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setTranslateX(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getTranslateX();
+                    }
+                };
+
+        private static final Property<VGroup, Float> TRANSLATE_Y =
+                new FloatProperty<VGroup> ("translateY") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setTranslateY(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getTranslateY();
+                    }
+        };
+
+        private static final Property<VGroup, Float> SCALE_X =
+                new FloatProperty<VGroup> ("scaleX") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setScaleX(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getScaleX();
+                    }
+                };
+
+        private static final Property<VGroup, Float> SCALE_Y =
+                new FloatProperty<VGroup> ("scaleY") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setScaleY(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getScaleY();
+                    }
+                };
+
+        private static final Property<VGroup, Float> PIVOT_X =
+                new FloatProperty<VGroup> ("pivotX") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setPivotX(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getPivotX();
+                    }
+                };
+
+        private static final Property<VGroup, Float> PIVOT_Y =
+                new FloatProperty<VGroup> ("pivotY") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setPivotY(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getPivotY();
+                    }
+                };
+
+        private static final Property<VGroup, Float> ROTATION =
+                new FloatProperty<VGroup> ("rotation") {
+                    @Override
+                    public void setValue(VGroup object, float value) {
+                        object.setRotation(value);
+                    }
+
+                    @Override
+                    public Float get(VGroup object) {
+                        return object.getRotation();
+                    }
+                };
+
+        private static final HashMap<String, Property> sPropertyMap =
+                new HashMap<String, Property>() {
+                    {
+                        put("translateX", TRANSLATE_X);
+                        put("translateY", TRANSLATE_Y);
+                        put("scaleX", SCALE_X);
+                        put("scaleY", SCALE_Y);
+                        put("pivotX", PIVOT_X);
+                        put("pivotY", PIVOT_Y);
+                        put("rotation", ROTATION);
+                    }
+                };
         // Temp array to store transform values obtained from native.
         private float[] mTransform;
         /////////////////////////////////////////////////////
@@ -1055,6 +1189,15 @@
             mNativePtr = nCreateGroup();
         }
 
+        Property getProperty(String propertyName) {
+            if (sPropertyMap.containsKey(propertyName)) {
+                return sPropertyMap.get(propertyName);
+            } else {
+                // property not found
+                return null;
+            }
+        }
+
         public String getGroupName() {
             return mGroupName;
         }
@@ -1102,7 +1245,7 @@
                 throw new RuntimeException("Error: inconsistent property count");
             }
             float rotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation,
-                    mTransform[ROTATE_INDEX]);
+                    mTransform[ROTATION_INDEX]);
             float pivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX,
                     mTransform[PIVOT_X_INDEX]);
             float pivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY,
@@ -1288,6 +1431,27 @@
         String mPathName;
         @Config int mChangingConfigurations;
 
+        private static final Property<VPath, PathParser.PathData> PATH_DATA =
+                new Property<VPath, PathParser.PathData>(PathParser.PathData.class, "pathData") {
+                    @Override
+                    public void set(VPath object, PathParser.PathData data) {
+                        object.setPathData(data);
+                    }
+
+                    @Override
+                    public PathParser.PathData get(VPath object) {
+                        return object.getPathData();
+                    }
+                };
+
+        Property getProperty(String propertyName) {
+            if (PATH_DATA.getName().equals(propertyName)) {
+                return PATH_DATA;
+            }
+            // property not found
+            return null;
+        }
+
         public VPath() {
             // Empty constructor.
         }
@@ -1410,7 +1574,7 @@
 
         private static final int NATIVE_ALLOCATION_SIZE = 264;
         // Property map for animatable attributes.
-        private final static HashMap<String, Integer> sPropertyMap
+        private final static HashMap<String, Integer> sPropertyIndexMap
                 = new HashMap<String, Integer> () {
             {
                 put("strokeWidth", STROKE_WIDTH_INDEX);
@@ -1424,6 +1588,125 @@
             }
         };
 
+        // Below are the Properties that wrap the setters to avoid reflection overhead in animations
+        private static final Property<VFullPath, Float> STROKE_WIDTH =
+                new FloatProperty<VFullPath> ("strokeWidth") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setStrokeWidth(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getStrokeWidth();
+                    }
+                };
+
+        private static final Property<VFullPath, Integer> STROKE_COLOR =
+                new IntProperty<VFullPath> ("strokeColor") {
+                    @Override
+                    public void setValue(VFullPath object, int value) {
+                        object.setStrokeColor(value);
+                    }
+
+                    @Override
+                    public Integer get(VFullPath object) {
+                        return object.getStrokeColor();
+                    }
+                };
+
+        private static final Property<VFullPath, Float> STROKE_ALPHA =
+                new FloatProperty<VFullPath> ("strokeAlpha") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setStrokeAlpha(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getStrokeAlpha();
+                    }
+                };
+
+        private static final Property<VFullPath, Integer> FILL_COLOR =
+                new IntProperty<VFullPath>("fillColor") {
+                    @Override
+                    public void setValue(VFullPath object, int value) {
+                        object.setFillColor(value);
+                    }
+
+                    @Override
+                    public Integer get(VFullPath object) {
+                        return object.getFillColor();
+                    }
+                };
+
+        private static final Property<VFullPath, Float> FILL_ALPHA =
+                new FloatProperty<VFullPath> ("fillAlpha") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setFillAlpha(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getFillAlpha();
+                    }
+                };
+
+        private static final Property<VFullPath, Float> TRIM_PATH_START =
+                new FloatProperty<VFullPath> ("trimPathStart") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setTrimPathStart(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getTrimPathStart();
+                    }
+                };
+
+        private static final Property<VFullPath, Float> TRIM_PATH_END =
+                new FloatProperty<VFullPath> ("trimPathEnd") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setTrimPathEnd(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getTrimPathEnd();
+                    }
+                };
+
+        private static final Property<VFullPath, Float> TRIM_PATH_OFFSET =
+                new FloatProperty<VFullPath> ("trimPathOffset") {
+                    @Override
+                    public void setValue(VFullPath object, float value) {
+                        object.setTrimPathOffset(value);
+                    }
+
+                    @Override
+                    public Float get(VFullPath object) {
+                        return object.getTrimPathOffset();
+                    }
+                };
+
+        private final static HashMap<String, Property> sPropertyMap
+                = new HashMap<String, Property> () {
+            {
+                put("strokeWidth", STROKE_WIDTH);
+                put("strokeColor", STROKE_COLOR);
+                put("strokeAlpha", STROKE_ALPHA);
+                put("fillColor", FILL_COLOR);
+                put("fillAlpha", FILL_ALPHA);
+                put("trimPathStart", TRIM_PATH_START);
+                put("trimPathEnd", TRIM_PATH_END);
+                put("trimPathOffset", TRIM_PATH_OFFSET);
+            }
+        };
+
         // Temp array to store property data obtained from native getter.
         private byte[] mPropertyData;
         /////////////////////////////////////////////////////
@@ -1446,11 +1729,24 @@
             mFillColors = copy.mFillColors;
         }
 
+        Property getProperty(String propertyName) {
+            Property p = super.getProperty(propertyName);
+            if (p != null) {
+                return p;
+            }
+            if (sPropertyMap.containsKey(propertyName)) {
+                return sPropertyMap.get(propertyName);
+            } else {
+                // property not found
+                return null;
+            }
+        }
+
         int getPropertyIndex(String propertyName) {
-            if (!sPropertyMap.containsKey(propertyName)) {
+            if (!sPropertyIndexMap.containsKey(propertyName)) {
                 return -1;
             } else {
-                return sPropertyMap.get(propertyName);
+                return sPropertyIndexMap.get(propertyName);
             }
         }
 
@@ -1784,6 +2080,7 @@
         abstract boolean onStateChange(int[] state);
         abstract boolean isStateful();
         abstract int getNativeSize();
+        abstract Property getProperty(String propertyName);
     }
 
     private static native long nCreateTree(long rootGroupPtr);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index faf6a52..c9d4af6 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -256,6 +256,7 @@
     tests/unit/MatrixTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
     tests/unit/RenderNodeTests.cpp \
+    tests/unit/RenderPropertiesTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/SnapshotTests.cpp \
     tests/unit/StringUtilsTests.cpp \
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 909ed36..801fd87 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -100,6 +100,8 @@
 
     ANDROID_API virtual void destroy();
 
+    ANDROID_API virtual void detachAnimators() {}
+
 private:
     friend class AnimationHandle;
     void addAnimationHandle(AnimationHandle* handle);
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 4d65782..dc18018 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -274,6 +274,10 @@
     return playTime >= mDuration;
 }
 
+nsecs_t BaseRenderNodeAnimator::getRemainingPlayTime() {
+    return mPlayState == PlayState::Reversing ? mPlayTime : mDuration - mPlayTime;
+}
+
 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
     if (mPlayState < PlayState::Finished) {
         mPlayState = PlayState::Finished;
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fdae0f3..9476750 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -62,19 +62,23 @@
     }
     bool mayRunAsync() { return mMayRunAsync; }
     ANDROID_API void start();
-    ANDROID_API void reset();
+    ANDROID_API virtual void reset();
     ANDROID_API void reverse();
     // Terminates the animation at its current progress.
     ANDROID_API void cancel();
 
     // Terminates the animation and skip to the end of the animation.
-    ANDROID_API void end();
+    ANDROID_API virtual void end();
 
     void attach(RenderNode* target);
     virtual void onAttached() {}
     void detach() { mTarget = nullptr; }
-    void pushStaging(AnimationContext& context);
-    bool animate(AnimationContext& context);
+    ANDROID_API void pushStaging(AnimationContext& context);
+    ANDROID_API bool animate(AnimationContext& context);
+
+    // Returns the remaining time in ms for the animation. Note this should only be called during
+    // an animation on RenderThread.
+    ANDROID_API nsecs_t getRemainingPlayTime();
 
     bool isRunning() { return mPlayState == PlayState::Running
             || mPlayState == PlayState::Reversing; }
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index ea2e15b..6db345a 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -66,8 +66,13 @@
             offscreenBuffer->texture.id(), 0);
     GL_CHECKPOINT(LOW);
 
-    LOG_ALWAYS_FATAL_IF(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE,
-            "framebuffer incomplete!");
+    int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
+            "framebuffer incomplete, status %d, textureId %d, size %dx%d",
+            status,
+            offscreenBuffer->texture.id(),
+            offscreenBuffer->texture.width(),
+            offscreenBuffer->texture.height());
 
     // Change the viewport & ortho projection
     setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index b572bda..28be05c 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -45,7 +45,7 @@
         , regions(stdAllocator)
         , referenceHolders(stdAllocator)
         , functors(stdAllocator)
-        , pushStagingFunctors(stdAllocator)
+        , vectorDrawables(stdAllocator)
         , hasDrawOps(false) {
 }
 
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5b3227b..ccf71c6 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -69,6 +69,11 @@
 typedef DrawRenderNodeOp NodeOpType;
 #endif
 
+namespace VectorDrawable {
+class Tree;
+};
+typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
+
 /**
  * Holds data used in the playback a tree of DisplayLists.
  */
@@ -110,16 +115,6 @@
     LinearAllocator mReplayAllocator;
 };
 
-/**
- * Functor that can be used for objects with data in both UI thread and RT to keep the data
- * in sync. This functor, when added to DisplayList, will be call during DisplayList sync.
- */
-struct PushStagingFunctor {
-    PushStagingFunctor() {}
-    virtual ~PushStagingFunctor() {}
-    virtual void operator ()() {}
-};
-
 struct FunctorContainer {
     Functor* functor;
     GlFunctorLifecycleListener* listener;
@@ -161,7 +156,7 @@
 
     const LsaVector<const SkBitmap*>& getBitmapResources() const { return bitmapResources; }
     const LsaVector<FunctorContainer>& getFunctors() const { return functors; }
-    const LsaVector<PushStagingFunctor*>& getPushStagingFunctors() { return pushStagingFunctors; }
+    const LsaVector<VectorDrawableRoot*>& getVectorDrawables() { return vectorDrawables; }
 
     size_t addChild(NodeOpType* childOp);
 
@@ -203,10 +198,10 @@
     // List of functors
     LsaVector<FunctorContainer> functors;
 
-    // List of functors that need to be notified of pushStaging. Note that this list gets nothing
+    // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
     // but a callback during sync DisplayList, unlike the list of functors defined above, which
     // gets special treatment exclusive for webview.
-    LsaVector<PushStagingFunctor*> pushStagingFunctors;
+    LsaVector<VectorDrawableRoot*> vectorDrawables;
 
     bool hasDrawOps; // only used if !HWUI_NEW_OPS
 
diff --git a/libs/hwui/DisplayListCanvas.cpp b/libs/hwui/DisplayListCanvas.cpp
index ca968ce..bec66295 100644
--- a/libs/hwui/DisplayListCanvas.cpp
+++ b/libs/hwui/DisplayListCanvas.cpp
@@ -417,7 +417,7 @@
 
 void DisplayListCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
     mDisplayList->ref(tree);
-    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
+    mDisplayList->vectorDrawables.push_back(tree);
     addDrawOp(new (alloc()) DrawVectorDrawableOp(tree, tree->stagingProperties()->getBounds()));
 }
 
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index cb8e55f..b8a5ce6 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -86,7 +86,9 @@
             ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
                     layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
 
-            const Rect& layerDamage = layers.entries()[i].damage;
+            Rect layerDamage = layers.entries()[i].damage;
+            // TODO: ensure layer damage can't be larger than layer
+            layerDamage.doIntersect(0, 0, layer->viewportWidth, layer->viewportHeight);
             layerNode->computeOrdering();
 
             // map current light center into RenderNode's coordinate space
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index b29f91f..e416e0c 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -30,6 +30,11 @@
             interpolator, startDelay, duration, repeatCount);
     mAnimators.emplace_back(animator);
     setListener(new PropertyAnimatorSetListener(this));
+
+    // Check whether any child animator is infinite after adding it them to the set.
+    if (repeatCount == -1) {
+        mIsInfinite = true;
+    }
 }
 
 PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
@@ -78,15 +83,27 @@
 void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
     init();
     mOneShotListener = listener;
+    mRequestId++;
     BaseRenderNodeAnimator::start();
 }
 
 void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
     init();
     mOneShotListener = listener;
+    mRequestId++;
     BaseRenderNodeAnimator::reverse();
 }
 
+void PropertyValuesAnimatorSet::reset() {
+    mRequestId++;
+    BaseRenderNodeAnimator::reset();
+}
+
+void PropertyValuesAnimatorSet::end() {
+    mRequestId++;
+    BaseRenderNodeAnimator::end();
+}
+
 void PropertyValuesAnimatorSet::init() {
     if (mInitialized) {
         return;
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index c7ae7c0..49021bc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -43,6 +43,7 @@
     float mLatestFraction = 0.0f;
 };
 
+// TODO: This class should really be named VectorDrawableAnimator
 class ANDROID_API PropertyValuesAnimatorSet : public BaseRenderNodeAnimator {
 public:
     friend class PropertyAnimatorSetListener;
@@ -50,11 +51,19 @@
 
     void start(AnimationListener* listener);
     void reverse(AnimationListener* listener);
+    virtual void reset() override;
+    virtual void end() override;
 
     void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
             Interpolator* interpolators, int64_t startDelays,
             nsecs_t durations, int repeatCount);
     virtual uint32_t dirtyMask();
+    bool isInfinite() { return mIsInfinite; }
+    void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
+    VectorDrawableRoot* getVectorDrawable() const { return mVectorDrawable; }
+    AnimationListener* getOneShotListener() { return mOneShotListener.get(); }
+    void clearOneShotListener() { mOneShotListener = nullptr; }
+    uint32_t getRequestId() const { return mRequestId; }
 
 protected:
     virtual float getValue(RenderNode* target) const override;
@@ -69,6 +78,11 @@
     std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
     float mLastFraction = 0.0f;
     bool mInitialized = false;
+    VectorDrawableRoot* mVectorDrawable = nullptr;
+    bool mIsInfinite = false;
+    // This request id gets incremented (on UI thread only) when a new request to modfiy the
+    // lifecycle of an animation happens, namely when start/end/reset/reverse is called.
+    uint32_t mRequestId = 0;
 };
 
 class PropertyAnimatorSetListener : public AnimationListener {
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 0932d65..6ba0ab5 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -25,7 +25,27 @@
 
 using namespace VectorDrawable;
 
-float PropertyValuesHolder::getValueFromData(float fraction) {
+inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
+    return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction);
+}
+
+// TODO: Add a test for this
+void ColorEvaluator::evaluate(SkColor* outColor,
+        const SkColor& fromColor, const SkColor& toColor, float fraction) const {
+    U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction);
+    U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction);
+    U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction);
+    U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction);
+    *outColor = SkColorSetARGB(alpha, red, green, blue);
+}
+
+void PathEvaluator::evaluate(PathData* out,
+        const PathData& from, const PathData& to, float fraction) const {
+    VectorDrawableUtils::interpolatePaths(out, from, to, fraction);
+}
+
+template<typename T>
+const T PropertyValuesHolderImpl<T>::getValueFromData(float fraction) const {
     if (mDataSource.size() == 0) {
         LOG_ALWAYS_FATAL("No data source is defined");
         return 0;
@@ -41,57 +61,44 @@
     int lowIndex = floor(fraction);
     fraction -= lowIndex;
 
-    float value = mDataSource[lowIndex] * (1.0f - fraction)
-            + mDataSource[lowIndex + 1] * fraction;
+    T value;
+    mEvaluator->evaluate(&value, mDataSource[lowIndex], mDataSource[lowIndex + 1], fraction);
     return value;
 }
 
-void GroupPropertyValuesHolder::setFraction(float fraction) {
-    float animatedValue;
+template<typename T>
+const T PropertyValuesHolderImpl<T>::calculateAnimatedValue(float fraction) const {
     if (mDataSource.size() > 0) {
-        animatedValue = getValueFromData(fraction);
+        return getValueFromData(fraction);
     } else {
-        animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
+        T value;
+        mEvaluator->evaluate(&value, mStartValue, mEndValue, fraction);
+        return value;
     }
+}
+
+void GroupPropertyValuesHolder::setFraction(float fraction) {
+    float animatedValue = calculateAnimatedValue(fraction);
     mGroup->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
-inline U8CPU lerp(U8CPU fromValue, U8CPU toValue, float fraction) {
-    return (U8CPU) (fromValue * (1 - fraction) + toValue * fraction);
-}
-
-// TODO: Add a test for this
-SkColor FullPathColorPropertyValuesHolder::interpolateColors(SkColor fromColor, SkColor toColor,
-        float fraction) {
-    U8CPU alpha = lerp(SkColorGetA(fromColor), SkColorGetA(toColor), fraction);
-    U8CPU red = lerp(SkColorGetR(fromColor), SkColorGetR(toColor), fraction);
-    U8CPU green = lerp(SkColorGetG(fromColor), SkColorGetG(toColor), fraction);
-    U8CPU blue = lerp(SkColorGetB(fromColor), SkColorGetB(toColor), fraction);
-    return SkColorSetARGB(alpha, red, green, blue);
-}
-
 void FullPathColorPropertyValuesHolder::setFraction(float fraction) {
-    SkColor animatedValue = interpolateColors(mStartValue, mEndValue, fraction);
+    SkColor animatedValue = calculateAnimatedValue(fraction);
     mFullPath->mutateProperties()->setColorPropertyValue(mPropertyId, animatedValue);
 }
 
 void FullPathPropertyValuesHolder::setFraction(float fraction) {
-    float animatedValue;
-    if (mDataSource.size() > 0) {
-        animatedValue = getValueFromData(fraction);
-    } else {
-        animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
-    }
+    float animatedValue = calculateAnimatedValue(fraction);
     mFullPath->mutateProperties()->setPropertyValue(mPropertyId, animatedValue);
 }
 
 void PathDataPropertyValuesHolder::setFraction(float fraction) {
-    VectorDrawableUtils::interpolatePaths(&mPathData, mStartValue, mEndValue, fraction);
+    mEvaluator->evaluate(&mPathData, mStartValue, mEndValue, fraction);
     mPath->mutateProperties()->setData(mPathData);
 }
 
 void RootAlphaPropertyValuesHolder::setFraction(float fraction) {
-    float animatedValue = mStartValue * (1 - fraction) + mEndValue * fraction;
+    float animatedValue = calculateAnimatedValue(fraction);
     mTree->mutateProperties()->setRootAlpha(animatedValue);
 }
 
diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h
index b905fae..432f8ba 100644
--- a/libs/hwui/PropertyValuesHolder.h
+++ b/libs/hwui/PropertyValuesHolder.h
@@ -31,91 +31,130 @@
 class ANDROID_API PropertyValuesHolder {
 public:
     virtual void setFraction(float fraction) = 0;
-    void setPropertyDataSource(float* dataSource, int length) {
-        mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length);
-    }
-   float getValueFromData(float fraction);
-   virtual ~PropertyValuesHolder() {}
-protected:
-   std::vector<float> mDataSource;
+    virtual ~PropertyValuesHolder() {}
 };
 
-class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolder {
+template <typename T>
+class Evaluator {
+public:
+    virtual void evaluate(T* out, const T& from, const T& to, float fraction) const {};
+    virtual ~Evaluator() {}
+};
+
+class FloatEvaluator : public Evaluator<float> {
+public:
+    virtual void evaluate(float* out, const float& from, const float& to, float fraction)
+            const override {
+        *out = from * (1 - fraction) + to * fraction;
+    }
+};
+
+class ANDROID_API ColorEvaluator : public Evaluator<SkColor> {
+public:
+    virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to,
+            float fraction) const override;
+};
+
+class ANDROID_API PathEvaluator : public Evaluator<PathData> {
+    virtual void evaluate(PathData* out, const PathData& from, const PathData& to, float fraction)
+            const override;
+};
+
+template <typename T>
+class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder {
+public:
+    PropertyValuesHolderImpl(const T& startValue, const T& endValue)
+            : mStartValue(startValue)
+            , mEndValue(endValue) {}
+    void setPropertyDataSource(T* dataSource, int length) {
+        mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length);
+    }
+    // Calculate the animated value from the data source.
+    const T getValueFromData(float fraction) const;
+    // Convenient method to favor getting animated value from data source. If no data source is set
+    // fall back to linear interpolation.
+    const T calculateAnimatedValue(float fraction) const;
+protected:
+   std::unique_ptr<Evaluator<T>> mEvaluator = nullptr;
+   // This contains uniformly sampled data throughout the animation duration. The first element
+   // should be the start value and the last should be the end value of the animation. When the
+   // data source is set, we'll favor data source over the linear interpolation of start/end value
+   // for calculation of animated value.
+   std::vector<T> mDataSource;
+   T mStartValue;
+   T mEndValue;
+};
+
+class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
 public:
     GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
             float endValue)
-            : mGroup(ptr)
-            , mPropertyId(propertyId)
-            , mStartValue(startValue)
-            , mEndValue(endValue){
+            : PropertyValuesHolderImpl(startValue, endValue)
+            , mGroup(ptr)
+            , mPropertyId(propertyId) {
+        mEvaluator.reset(new FloatEvaluator());
     }
     void setFraction(float fraction) override;
 private:
     VectorDrawable::Group* mGroup;
     int mPropertyId;
-    float mStartValue;
-    float mEndValue;
 };
 
-class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolder {
+class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
 public:
-    FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, int32_t startValue,
-            int32_t endValue)
-            : mFullPath(ptr)
-            , mPropertyId(propertyId)
-            , mStartValue(startValue)
-            , mEndValue(endValue) {};
+    FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId,
+            SkColor startValue, SkColor endValue)
+            : PropertyValuesHolderImpl(startValue, endValue)
+            , mFullPath(ptr)
+            , mPropertyId(propertyId) {
+        mEvaluator.reset(new ColorEvaluator());
+    }
     void setFraction(float fraction) override;
     static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction);
 private:
     VectorDrawable::FullPath* mFullPath;
     int mPropertyId;
-    int32_t mStartValue;
-    int32_t mEndValue;
 };
 
-class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolder {
+class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
 public:
     FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
             float endValue)
-            : mFullPath(ptr)
-            , mPropertyId(propertyId)
-            , mStartValue(startValue)
-            , mEndValue(endValue) {};
+            : PropertyValuesHolderImpl(startValue, endValue)
+            , mFullPath(ptr)
+            , mPropertyId(propertyId) {
+        mEvaluator.reset(new FloatEvaluator());
+    };
     void setFraction(float fraction) override;
 private:
     VectorDrawable::FullPath* mFullPath;
     int mPropertyId;
-    float mStartValue;
-    float mEndValue;
 };
 
-class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolder {
+class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
 public:
     PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
             PathData* endValue)
-            : mPath(ptr)
-            , mStartValue(*startValue)
-            , mEndValue(*endValue) {};
+            : PropertyValuesHolderImpl(*startValue, *endValue)
+            , mPath(ptr) {
+        mEvaluator.reset(new PathEvaluator());
+    };
     void setFraction(float fraction) override;
 private:
     VectorDrawable::Path* mPath;
     PathData mPathData;
-    PathData mStartValue;
-    PathData mEndValue;
 };
 
-class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolder {
+class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
 public:
     RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
-            : mTree(tree)
-            , mStartValue(startValue)
-            , mEndValue(endValue) {}
+            : PropertyValuesHolderImpl(startValue, endValue)
+            , mTree(tree) {
+        mEvaluator.reset(new FloatEvaluator());
+    }
     void setFraction(float fraction) override;
 private:
     VectorDrawable::Tree* mTree;
-    float mStartValue;
-    float mEndValue;
 };
 }
 }
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index b49f9b5..b35c926 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -440,8 +440,8 @@
 }
 
 void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
-    mDisplayList->pushStagingFunctors.push_back(tree->getFunctor());
     mDisplayList->ref(tree);
+    mDisplayList->vectorDrawables.push_back(tree);
     addOp(alloc().create_trivial<VectorDrawableOp>(
             tree,
             Rect(tree->stagingProperties()->getBounds()),
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6e848fd..5a3300a 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -319,6 +319,8 @@
         transformUpdateNeeded = true;
     } else if (!layerMatchesWidthAndHeight(mLayer, getWidth(), getHeight())) {
 #if HWUI_NEW_OPS
+        // TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
+        // Or, ideally, maintain damage between frames on node/layer so ordering is always correct
         RenderState& renderState = mLayer->renderState;
         if (properties().fitsOnLayer()) {
             mLayer = renderState.layerPool().resize(mLayer, getWidth(), getHeight());
@@ -419,6 +421,16 @@
     prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
     pushLayerUpdate(info);
 
+    if (mDisplayList) {
+        for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+            // If any vector drawable in the display list needs update, damage the node.
+            if (vectorDrawable->isDirty()) {
+                damageSelf(info);
+            }
+            vectorDrawable->setPropertyChangeWillBeConsumed(true);
+        }
+    }
+
     info.damageAccumulator->popTransform();
 }
 
@@ -477,8 +489,8 @@
         for (auto& iter : mDisplayList->getFunctors()) {
             (*iter.functor)(DrawGlInfo::kModeSync, nullptr);
         }
-        for (size_t i = 0; i < mDisplayList->getPushStagingFunctors().size(); i++) {
-            (*mDisplayList->getPushStagingFunctors()[i])();
+        for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
+            vectorDrawable->syncProperties();
         }
     }
 }
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 3952798..696cc29 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -611,7 +611,9 @@
     bool fitsOnLayer() const {
         const DeviceInfo* deviceInfo = DeviceInfo::get();
         return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
-                        && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+                        && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize()
+                        && mPrimitiveFields.mWidth > 0
+                        && mPrimitiveFields.mHeight > 0;
     }
 
     bool promotedToLayer() const {
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index a5d1d4b..e67dfdd 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -673,21 +673,16 @@
     void onPropertyChanged(TreeProperties* prop);
     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
     const TreeProperties* stagingProperties() const { return &mStagingProperties; }
-    PushStagingFunctor* getFunctor() { return &mFunctor;}
 
     // This should only be called from animations on RT
     TreeProperties* mutateProperties() { return &mProperties; }
 
+    // This should always be called from RT.
+    bool isDirty() const { return mCache.dirty; }
+    bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
+    void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
+
 private:
-    class VectorDrawableFunctor : public PushStagingFunctor {
-    public:
-        VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
-        virtual void operator ()() {
-            mTree->syncProperties();
-        }
-    private:
-        Tree* mTree;
-    };
 
     SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
     bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
@@ -704,8 +699,6 @@
     TreeProperties mProperties = TreeProperties(this);
     TreeProperties mStagingProperties = TreeProperties(this);
 
-    VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
-
     SkPaint mPaint;
     struct Cache {
         SkBitmap bitmap;
@@ -717,6 +710,8 @@
 
     PropertyChangedListener mPropertyChangedListener
             = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+
+    mutable bool mWillBeConsumed = false;
 };
 
 } // namespace VectorDrawable
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index e6399d4..d4956be 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -149,6 +149,8 @@
             if (mEglManager.isCurrent(mEglSurface)) {
                 mEglManager.makeCurrent(EGL_NO_SURFACE);
             }
+        } else if (mIsDirty && hasSurface()) {
+            mRenderThread.postFrameCallback(this);
         }
     }
 }
@@ -231,6 +233,8 @@
     freePrefetchedLayers(info.observer);
     GL_CHECKPOINT(MODERATE);
 
+    mIsDirty = true;
+
     if (CC_UNLIKELY(!mNativeSurface.get())) {
         mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
         info.out.canDrawThisFrame = false;
@@ -278,6 +282,7 @@
 
 void CanvasContext::stopDrawing() {
     mRenderThread.removeFrameCallback(this);
+    mAnimationContext->detachAnimators();
 }
 
 void CanvasContext::notifyFramePending() {
@@ -503,6 +508,7 @@
     // Even if we decided to cancel the frame, from the perspective of jank
     // metrics the frame was swapped at this point
     mCurrentFrameInfo->markSwapBuffers();
+    mIsDirty = false;
 
     if (drew || mEglManager.damageRequiresSwap()) {
         if (CC_UNLIKELY(!mEglManager.swapBuffers(frame, screenDirty))) {
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index e739b29..a6eb7ad 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -187,7 +187,12 @@
     EglManager& mEglManager;
     sp<Surface> mNativeSurface;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
+    // stopped indicates the CanvasContext will reject actual redraw operations,
+    // and defer repaint until it is un-stopped
     bool mStopped = false;
+    // CanvasContext is dirty if it has received an update that it has not
+    // painted onto its surface.
+    bool mIsDirty = false;
     bool mBufferPreserved = false;
     SwapBehavior mSwapBehavior = kSwap_default;
     struct SwapHistory {
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index b2997df..cf76a86 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -16,13 +16,26 @@
 
 #include <gtest/gtest.h>
 
+#include "AnimationContext.h"
+#include "DamageAccumulator.h"
+#include "IContextFactory.h"
 #include "RenderNode.h"
 #include "TreeInfo.h"
+#include "renderthread/CanvasContext.h"
 #include "tests/common/TestUtils.h"
 #include "utils/Color.h"
 
 using namespace android;
 using namespace android::uirenderer;
+using namespace android::uirenderer::renderthread;
+
+class ContextFactory : public android::uirenderer::IContextFactory {
+public:
+    android::uirenderer::AnimationContext* createAnimationContext
+        (android::uirenderer::renderthread::TimeLord& clock) override {
+        return new android::uirenderer::AnimationContext(clock);
+    }
+};
 
 TEST(RenderNode, hasParents) {
     auto child = TestUtils::createNode(0, 0, 200, 400,
@@ -89,3 +102,31 @@
     TestUtils::syncHierarchyPropertiesAndDisplayList(node);
     EXPECT_EQ(0, refcnt);
 }
+
+RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
+    ContextFactory contextFactory;
+    CanvasContext canvasContext(renderThread, false, nullptr, &contextFactory);
+    TreeInfo info(TreeInfo::MODE_RT_ONLY, canvasContext);
+    DamageAccumulator damageAccumulator;
+    info.damageAccumulator = &damageAccumulator;
+    info.observer = nullptr;
+
+    {
+        auto nonNullDLNode = TestUtils::createNode(0, 0, 200, 400,
+                [](RenderProperties& props, TestCanvas& canvas) {
+            canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+        });
+        TestUtils::syncHierarchyPropertiesAndDisplayList(nonNullDLNode);
+        EXPECT_TRUE(nonNullDLNode->getDisplayList());
+        nonNullDLNode->prepareTree(info);
+    }
+
+    {
+        auto nullDLNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
+        TestUtils::syncHierarchyPropertiesAndDisplayList(nullDLNode);
+        EXPECT_FALSE(nullDLNode->getDisplayList());
+        nullDLNode->prepareTree(info);
+    }
+
+    canvasContext.destroy(nullptr);
+}
diff --git a/libs/hwui/tests/unit/RenderPropertiesTests.cpp b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
new file mode 100644
index 0000000..9001098
--- /dev/null
+++ b/libs/hwui/tests/unit/RenderPropertiesTests.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <RenderProperties.h>
+
+using namespace android;
+using namespace android::uirenderer;
+
+TEST(RenderProperties, layerValidity) {
+    DeviceInfo::initialize();
+
+    const int maxTextureSize = DeviceInfo::get()->maxTextureSize();
+    ASSERT_LE(2048, maxTextureSize);
+    ASSERT_GT(100000, maxTextureSize);
+
+    RenderProperties props;
+
+    // simple cases that all should fit on layers
+    props.setLeftTopRightBottom(0, 0, 100, 100);
+    ASSERT_TRUE(props.fitsOnLayer());
+    props.setLeftTopRightBottom(100, 2000, 300, 4000);
+    ASSERT_TRUE(props.fitsOnLayer());
+    props.setLeftTopRightBottom(-10, -10, 510, 512);
+    ASSERT_TRUE(props.fitsOnLayer());
+
+    // Too big - can't have layer bigger than max texture size
+    props.setLeftTopRightBottom(0, 0, maxTextureSize + 1, maxTextureSize + 1);
+    ASSERT_FALSE(props.fitsOnLayer());
+
+    // Too small - can't have 0 dimen layer
+    props.setLeftTopRightBottom(0, 0, 100, 0);
+    ASSERT_FALSE(props.fitsOnLayer());
+}
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 3f6081b..4d40e6b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -709,6 +709,8 @@
      * played.
      *
      * @param sh the SurfaceHolder to use for video display
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized or has been released.
      */
     public void setDisplay(SurfaceHolder sh) {
         mSurfaceHolder = sh;
@@ -739,6 +741,8 @@
      *
      * @param surface The {@link Surface} to be used for the video portion of
      * the media.
+     * @throws IllegalStateException if the internal player engine has not been
+     * initialized or has been released.
      */
     public void setSurface(Surface surface) {
         if (mScreenOnWhilePlaying && surface != null) {
diff --git a/packages/CtsShim/Android.mk b/packages/CtsShim/Android.mk
index cd5b288..fa6423e 100644
--- a/packages/CtsShim/Android.mk
+++ b/packages/CtsShim/Android.mk
@@ -53,3 +53,4 @@
 
 include $(BUILD_PREBUILT)
 
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index b550c1c..bf6ae41 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -17,25 +17,6 @@
 LOCAL_PATH := $(my-dir)
 
 ###########################################################
-# Variant: Privileged app
-
-include $(CLEAR_VARS)
-# this needs to be a privileged application
-LOCAL_PRIVILEGED_MODULE := true
-
-LOCAL_MODULE_TAGS := optional
-LOCAL_SDK_VERSION := current
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_DEX_PREOPT := false
-
-LOCAL_PACKAGE_NAME := CtsShimPriv
-
-LOCAL_MANIFEST_FILE := shim_priv/AndroidManifest.xml
-
-include $(BUILD_PACKAGE)
-
-
-###########################################################
 # Variant: Privileged app upgrade
 
 include $(CLEAR_VARS)
@@ -52,7 +33,34 @@
 LOCAL_MANIFEST_FILE := shim_priv_upgrade/AndroidManifest.xml
 
 include $(BUILD_PACKAGE)
+my_shim_priv_upgrade_apk := $(LOCAL_BUILT_MODULE)
 
+###########################################################
+# Variant: Privileged app
+
+include $(CLEAR_VARS)
+# this needs to be a privileged application
+LOCAL_PRIVILEGED_MODULE := true
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_SDK_VERSION := current
+LOCAL_PROGUARD_ENABLED := disabled
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PACKAGE_NAME := CtsShimPriv
+
+# Generate the upgrade key by taking the hash of the built CtsShimPrivUpgrade apk
+gen := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,true)/AndroidManifest.xml
+$(gen): PRIVATE_CUSTOM_TOOL = sed -e "s/__HASH__/`sha512sum $(PRIVATE_INPUT_APK) | cut -d' ' -f1`/" $< >$@
+$(gen): PRIVATE_INPUT_APK := $(my_shim_priv_upgrade_apk)
+$(gen): $(LOCAL_PATH)/shim_priv/AndroidManifest.xml $(my_shim_priv_upgrade_apk)
+	$(transform-generated-source)
+
+my_shim_priv_upgrade_apk :=
+
+LOCAL_FULL_MANIFEST_FILE := $(gen)
+
+include $(BUILD_PACKAGE)
 
 ###########################################################
 # Variant: System app
diff --git a/packages/CtsShim/build/README b/packages/CtsShim/build/README
index 1f154e1..333b87c 100644
--- a/packages/CtsShim/build/README
+++ b/packages/CtsShim/build/README
@@ -6,31 +6,18 @@
 NOTE: The need to include a binary on the system image may be deprecated if a
 solution involving a temporarily writable /system partition is implemented.
 
-MAKING THE PREBUILTS
-In order to generate the upgrade key, the shim directory needs to be built multiple
-times. First to generate the upgrade APK [so its hash can be obtained] and again
-once the hash has been included as part of the pre-installed APK.
-
 build:
-    $ mmm frameworks/base/packages/CtsShim/build
+    $ tapas CtsShim CtsShimPriv CtsShimPrivUpgrade
+    $ m
 
-update the manifest:
-    $ sed -i -e "s/__HASH__/`sha512sum out/target/product/shamu/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk | cut -d' ' -f1`/" \
-        frameworks/base/packages/CtsShim/build/shim_priv/AndroidManifest.xml
-
-build:
-    $ mmm frameworks/base/packages/CtsShim/build
-
-update prebuilts:
-    $ cp out/target/product/shamu/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
+local testing:
+    $ cp $OUT/system/priv-app/CtsShimPrivUpgrade/CtsShimPrivUpgrade.apk \
         cts/hostsidetests/appsecurity/test-apps/PrivilegedUpdateApp
-    $ cp out/target/product/shamu/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
+    $ cp $OUT/system/priv-app/CtsShimPriv/CtsShimPriv.apk \
         frameworks/base/packages/CtsShim
-    $ cp out/target/product/shamu/system/app/CtsShim/CtsShim.apk \
+    $ cp $OUT/system/app/CtsShim/CtsShim.apk \
         frameworks/base/packages/CtsShim
 
-revert manifest:
-    $ pushd frameworks/base && git checkout -- packages/CtsShim/build/shim_priv/AndroidManifest.xml && popd
-
-Finally, upload and submit both the cts/ and frameworks/base/ repos.
+For final submission, the APKs should be downloaded from the build server, then
+submitted to the cts/ and frameworks/base/ repos.
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
index b0e5e4e..6588ee1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
@@ -20,6 +20,7 @@
 import static android.os.Environment.STANDARD_DIRECTORIES;
 import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
 import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
+
 import static com.android.documentsui.LocalPreferences.getScopedAccessPermissionStatus;
 import static com.android.documentsui.LocalPreferences.PERMISSION_ASK;
 import static com.android.documentsui.LocalPreferences.PERMISSION_ASK_AGAIN;
@@ -201,14 +202,23 @@
         final List<VolumeInfo> volumes = sm.getVolumes();
         if (DEBUG) Log.d(TAG, "Number of volumes: " + volumes.size());
         File internalRoot = null;
+        boolean found = true;
         for (VolumeInfo volume : volumes) {
             if (isRightVolume(volume, root, userId)) {
+                found = true;
                 internalRoot = volume.getInternalPathForUser(userId);
                 // Must convert path before calling getDocIdForFileCreateNewDir()
                 if (DEBUG) Log.d(TAG, "Converting " + root + " to " + internalRoot);
                 file = isRoot ? internalRoot : new File(internalRoot, directory);
+                volumeUuid = storageVolume.getUuid();
                 volumeLabel = sm.getBestVolumeDescription(volume);
-                volumeUuid = volume.getFsUuid();
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = storageVolume.getDescription(activity);
+                }
+                if (TextUtils.isEmpty(volumeLabel)) {
+                    volumeLabel = activity.getString(android.R.string.unknownName);
+                    Log.w(TAG, "No volume description  for " + volume + "; using " + volumeLabel);
+                }
                 break;
             }
         }
@@ -229,7 +239,7 @@
             return true;
         }
 
-        if (volumeLabel == null) {
+        if (!found) {
             Log.e(TAG, "Could not get volume for " + file);
             logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
@@ -277,15 +287,16 @@
     private static boolean isRightVolume(VolumeInfo volume, String root, int userId) {
         final File userPath = volume.getPathForUser(userId);
         final String path = userPath == null ? null : volume.getPathForUser(userId).getPath();
-        final boolean isVisible = volume.isVisibleForWrite(userId);
+        final boolean isMounted = volume.isMountedReadable();
         if (DEBUG)
-            Log.d(TAG, "Volume: " + volume + " userId: " + userId + " root: " + root
-                    + " volumePath: " + volume.getPath().getPath()
-                    + " pathForUser: " + path
-                    + " internalPathForUser: " + volume.getInternalPath()
-                    + " isVisible: " + isVisible);
+            Log.d(TAG, "Volume: " + volume
+                    + "\n\tuserId: " + userId
+                    + "\n\tuserPath: " + userPath
+                    + "\n\troot: " + root
+                    + "\n\tpath: " + path
+                    + "\n\tisMounted: " + isMounted);
 
-        return volume.isVisibleForWrite(userId) && root.equals(path);
+        return isMounted && root.equals(path);
     }
 
     private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
@@ -455,7 +466,7 @@
                 message = TextUtils.expandTemplate(
                         getText(mIsPrimary ? R.string.open_external_dialog_request_primary_volume
                                 : R.string.open_external_dialog_request),
-                        mAppLabel, directory, mVolumeLabel);
+                                mAppLabel, directory, mVolumeLabel);
             }
             final TextView messageField = (TextView) view.findViewById(R.id.message);
             messageField.setText(message);
diff --git a/packages/PrintRecommendationService/AndroidManifest.xml b/packages/PrintRecommendationService/AndroidManifest.xml
index 0eb218c..c6736d7 100644
--- a/packages/PrintRecommendationService/AndroidManifest.xml
+++ b/packages/PrintRecommendationService/AndroidManifest.xml
@@ -17,7 +17,12 @@
  */
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.printservice.recommendation">
+    package="com.android.printservice.recommendation"
+    android:versionCode="1"
+    android:versionName="1.0.0">
+
+    <uses-sdk android:minSdkVersion="24"
+        android:targetSdkVersion="24" />
 
     <uses-permission android:name="android.permission.INTERNET" />
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index e071f6a..284827b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -28,13 +28,10 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.SparseArray;
-import android.view.View;
 import android.widget.TextView;
 
 import com.android.settingslib.R;
 
-import java.util.Objects;
-
 public class AccessPointPreference extends Preference {
 
     private static final int[] STATE_SECURED = {
@@ -111,7 +108,6 @@
             mTitleView.setCompoundDrawablePadding(mBadgePadding);
         }
         view.itemView.setContentDescription(mContentDescription);
-        view.itemView.setAccessibilityLiveRegion(View.ACCESSIBILITY_LIVE_REGION_POLITE);
     }
 
     protected void updateIcon(int level, Context context) {
@@ -152,7 +148,6 @@
      * Updates the title and summary; may indirectly call notifyChanged().
      */
     public void refresh() {
-        boolean updated = false;
         if (mForSavedNetworks) {
             setTitle(mAccessPoint.getConfigName());
         } else {
@@ -164,28 +159,21 @@
         if (level != mLevel) {
             mLevel = level;
             updateIcon(mLevel, context);
-            updated = true;
+            notifyChanged();
         }
         updateBadge(context);
 
         setSummary(mForSavedNetworks ? mAccessPoint.getSavedNetworkSummary()
                 : mAccessPoint.getSettingsSummary());
 
-        CharSequence contentDescription = getTitle();
+        mContentDescription = getTitle();
         if (getSummary() != null) {
-            contentDescription = TextUtils.concat(contentDescription, ",", getSummary());
+            mContentDescription = TextUtils.concat(mContentDescription, ",", getSummary());
         }
         if (level >= 0 && level < WIFI_CONNECTION_STRENGTH.length) {
-            contentDescription = TextUtils.concat(contentDescription, ",",
+            mContentDescription = TextUtils.concat(mContentDescription, ",",
                     getContext().getString(WIFI_CONNECTION_STRENGTH[level]));
         }
-        if (!Objects.equals(contentDescription, mContentDescription)) {
-            mContentDescription = contentDescription;
-            updated = true;
-        }
-        if (updated) {
-            notifyChanged();
-        }
     }
 
     @Override
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 9c0aa35..2efefb3 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -90,7 +90,7 @@
     <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
-    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.CREATE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
     <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS" />
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 19d612d..603d1e0 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -402,16 +402,16 @@
     <string name="monitoring_title" msgid="169206259253048106">"Overvågning af netværk"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"Deaktiver VPN"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"Afbryd VPN-forbindelse"</string>
-    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds placeringsoplysninger. Kontakt din administrator, hvis du vil have flere oplysninger."</string>
+    <string name="monitoring_description_device_owned" msgid="5780988291898461883">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds stedoplysninger. Kontakt din administrator, hvis du vil have flere oplysninger."</string>
     <string name="monitoring_description_vpn" msgid="4445150119515393526">"Du gav en app tilladelse til at konfigurere en VPN-forbindelse.\n\nDenne app kan overvåge din enhed og netværksaktivitet, bl.a. e-mails, apps og websites."</string>
-    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds placeringsoplysninger.\n\nDu har forbindelse til et VPN, som kan overvåge din netværksaktivitet, herunder e-mails, apps og websites.\n\nKontakt din administrator, hvis du vil have flere oplysninger."</string>
+    <string name="monitoring_description_vpn_device_owned" msgid="3090670777499161246">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedsadgang, apps, data, der er knyttet til din enhed, og din enheds stedoplysninger.\n\nDu har forbindelse til et VPN, som kan overvåge din netværksaktivitet, herunder e-mails, apps og websites.\n\nKontakt din administrator, hvis du vil have flere oplysninger."</string>
     <string name="monitoring_description_vpn_profile_owned" msgid="2054949132145039290">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger.\n\nDu er også forbundet til en VPN-forbindelse, som kan overvåge din netværksaktivitet."</string>
     <string name="legacy_vpn_name" msgid="6604123105765737830">"VPN"</string>
     <string name="monitoring_description_app" msgid="6259179342284742878">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_app_personal" msgid="484599052118316268">"Du har forbindelse til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåge din private netværksaktivitet, bl.a. e-mails, apps og websites."</string>
     <string name="monitoring_description_app_work" msgid="1754325860918060897">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
     <string name="monitoring_description_app_personal_work" msgid="4946600443852045903">"Din arbejdsprofil administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Den er forbundet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåge din arbejdsrelaterede netværksaktivitet, bl.a. e-mails, apps og websites.\n\nDu er også forbundet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåge din private netværksaktivitet."</string>
-    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens placeringsoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
+    <string name="monitoring_description_vpn_app_device_owned" msgid="4970443827043261703">"Din enhed administreres af <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nDin administrator kan overvåge og administrere indstillinger, virksomhedens adgang, data tilknyttet din enhed og enhedens stedoplysninger.\n\nDu er forbundet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåge din netværksaktivitet, bl.a. e-mails, apps og websites.\n\nKontakt din administrator for at få flere oplysninger."</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheden vil forblive låst, indtil du manuelt låser den op"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Modtag underretninger hurtigere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem, før du låser op"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 01dcee2..5d01d15 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -153,7 +153,7 @@
     <string name="accessibility_cell_data_on" msgid="4310018593519761767">"Բջջային տվյալներն ակտիվ են"</string>
     <string name="accessibility_cell_data_off" msgid="8000803571751407635">"Բջջային ցանցով տվյալների փոխանցումն անջատված է"</string>
     <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Bluetooth-ը կապվում է:"</string>
-    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Ինքնաթիռային ռեժիմ"</string>
+    <string name="accessibility_airplane_mode" msgid="834748999790763092">"Ինքնաթիռի ռեժիմ"</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"SIM քարտ չկա:"</string>
     <string name="accessibility_carrier_network_change_mode" msgid="4017301580441304305">"Օպերատորի ցանցի փոփոխում:"</string>
     <string name="accessibility_battery_details" msgid="7645516654955025422">"Բացել մարտկոցի տվյալները"</string>
@@ -189,10 +189,10 @@
     <string name="accessibility_quick_settings_wifi_changed_on" msgid="6440117170789528622">"Wifi-ը միացավ:"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Շարժական <xliff:g id="SIGNAL">%1$s</xliff:g>: <xliff:g id="TYPE">%2$s</xliff:g>: <xliff:g id="NETWORK">%3$s</xliff:g>:"</string>
     <string name="accessibility_quick_settings_battery" msgid="1480931583381408972">"Մարտկոցը <xliff:g id="STATE">%s</xliff:g> է:"</string>
-    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Ինքնաթիռային ռեժիմն անջատված է:"</string>
-    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ինքնաթիռային ռեժիմը միացված է:"</string>
-    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ինքնաթիռային ռեժիմն անջատվեց:"</string>
-    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռային ռեժիմը միացավ:"</string>
+    <string name="accessibility_quick_settings_airplane_off" msgid="7786329360056634412">"Ինքնաթիռի ռեժիմն անջատված է:"</string>
+    <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Ինքնաթիռի ռեժիմը միացված է:"</string>
+    <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Ինքնաթիռի ռեժիմն անջատվեց:"</string>
+    <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Ինքնաթիռի ռեժիմը միացավ:"</string>
     <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"Չխանգարելու ընտրանքը միացված է: Ընդհատել միայն կարևոր ծանուցումների դեպքում:"</string>
     <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"Չանհանգստացնել՝ ընդհանուր լուռ վիճակը:"</string>
     <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"Չանհանգստացնել՝ միայն զարթուցիչ"</string>
@@ -451,7 +451,7 @@
     <string name="status_bar_ethernet" msgid="5044290963549500128">"Ethernet"</string>
     <string name="status_bar_alarm" msgid="8536256753575881818">"Զարթուցիչ"</string>
     <string name="status_bar_work" msgid="6022553324802866373">"Android for Work-ի պրոֆիլ"</string>
-    <string name="status_bar_airplane" msgid="7057575501472249002">"Ինքնաթիռային ռեժիմ"</string>
+    <string name="status_bar_airplane" msgid="7057575501472249002">"Ինքնաթիռի ռեժիմ"</string>
     <string name="add_tile" msgid="2995389510240786221">"Սալիկի ավելացում"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Սալիկի հեռարձակում"</string>
     <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Ժամը <xliff:g id="WHEN">%1$s</xliff:g>-ի զարթուցիչը չի զանգի, եթե մինչ այդ չանջատեք այս կարգավորումը"</string>
diff --git a/packages/SystemUI/src/com/android/systemui/Interpolators.java b/packages/SystemUI/src/com/android/systemui/Interpolators.java
index 17f4dab..fd3bd92 100644
--- a/packages/SystemUI/src/com/android/systemui/Interpolators.java
+++ b/packages/SystemUI/src/com/android/systemui/Interpolators.java
@@ -36,6 +36,7 @@
     public static final Interpolator ACCELERATE = new AccelerateInterpolator();
     public static final Interpolator ACCELERATE_DECELERATE = new AccelerateDecelerateInterpolator();
     public static final Interpolator DECELERATE_QUINT = new DecelerateInterpolator(2.5f);
+    public static final Interpolator CUSTOM_40_40 = new PathInterpolator(0.4f, 0f, 0.6f, 1f);
 
     /**
      * Interpolator to be used when animating a move based on a click. Pair with enough duration.
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
index 5878219..8bd38db 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistDisclosure.java
@@ -95,39 +95,34 @@
     private class AssistDisclosureView extends View
             implements ValueAnimator.AnimatorUpdateListener {
 
-        public static final int TRACING_ANIMATION_DURATION = 600;
-        public static final int ALPHA_IN_ANIMATION_DURATION = 450;
-        public static final int ALPHA_OUT_ANIMATION_DURATION = 400;
+        static final int FULL_ALPHA = 222; // 87%
+        static final int ALPHA_IN_ANIMATION_DURATION = 400;
+        static final int ALPHA_OUT_ANIMATION_DURATION = 300;
+
 
         private float mThickness;
         private float mShadowThickness;
         private final Paint mPaint = new Paint();
         private final Paint mShadowPaint = new Paint();
 
-        private final ValueAnimator mTracingAnimator;
         private final ValueAnimator mAlphaOutAnimator;
         private final ValueAnimator mAlphaInAnimator;
         private final AnimatorSet mAnimator;
 
-        private float mTracingProgress = 0;
         private int mAlpha = 0;
 
         public AssistDisclosureView(Context context) {
             super(context);
 
-            mTracingAnimator = ValueAnimator.ofFloat(0, 1).setDuration(TRACING_ANIMATION_DURATION);
-            mTracingAnimator.addUpdateListener(this);
-            mTracingAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
-                    R.interpolator.assist_disclosure_trace));
-            mAlphaInAnimator = ValueAnimator.ofInt(0, 255).setDuration(ALPHA_IN_ANIMATION_DURATION);
+            mAlphaInAnimator = ValueAnimator.ofInt(0, FULL_ALPHA)
+                    .setDuration(ALPHA_IN_ANIMATION_DURATION);
             mAlphaInAnimator.addUpdateListener(this);
-            mAlphaInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-            mAlphaOutAnimator = ValueAnimator.ofInt(255, 0).setDuration(
+            mAlphaInAnimator.setInterpolator(Interpolators.CUSTOM_40_40);
+            mAlphaOutAnimator = ValueAnimator.ofInt(FULL_ALPHA, 0).setDuration(
                     ALPHA_OUT_ANIMATION_DURATION);
             mAlphaOutAnimator.addUpdateListener(this);
-            mAlphaOutAnimator.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
+            mAlphaOutAnimator.setInterpolator(Interpolators.CUSTOM_40_40);
             mAnimator = new AnimatorSet();
-            mAnimator.play(mAlphaInAnimator).with(mTracingAnimator);
             mAnimator.play(mAlphaInAnimator).before(mAlphaOutAnimator);
             mAnimator.addListener(new AnimatorListenerAdapter() {
                 boolean mCancelled;
@@ -174,8 +169,6 @@
             super.onDetachedFromWindow();
 
             mAnimator.cancel();
-
-            mTracingProgress = 0;
             mAlpha = 0;
         }
 
@@ -197,45 +190,32 @@
             final int width = getWidth();
             final int height = getHeight();
             float thickness = mThickness;
-            final float pixelProgress = mTracingProgress * (width + height - 2 * thickness);
 
-            float bottomProgress = Math.min(pixelProgress, width / 2f);
-            if (bottomProgress > 0) {
-                drawBeam(canvas,
-                        width / 2f - bottomProgress,
-                        height - thickness,
-                        width / 2f + bottomProgress,
-                        height, paint, padding);
-            }
+            // bottom
+            drawBeam(canvas,
+                    0,
+                    height - thickness,
+                    width,
+                    height, paint, padding);
 
-            float sideProgress = Math.min(pixelProgress - bottomProgress, height - thickness);
-            if (sideProgress > 0) {
-                drawBeam(canvas,
-                        0,
-                        (height - thickness) - sideProgress,
-                        thickness,
-                        height - thickness, paint, padding);
-                drawBeam(canvas,
-                        width - thickness,
-                        (height - thickness) - sideProgress,
-                        width,
-                        height - thickness, paint, padding);
-            }
+            // sides
+            drawBeam(canvas,
+                    0,
+                    0,
+                    thickness,
+                    height - thickness, paint, padding);
+            drawBeam(canvas,
+                    width - thickness,
+                    0,
+                    width,
+                    height - thickness, paint, padding);
 
-            float topProgress = Math.min(pixelProgress - bottomProgress - sideProgress,
-                    width / 2 - thickness);
-            if (sideProgress > 0 && topProgress > 0) {
-                drawBeam(canvas,
-                        thickness,
-                        0,
-                        thickness + topProgress,
-                        thickness, paint, padding);
-                drawBeam(canvas,
-                        (width - thickness) - topProgress,
-                        0,
-                        width - thickness,
-                        thickness, paint, padding);
-            }
+            // top
+            drawBeam(canvas,
+                    thickness,
+                    0,
+                    width - thickness,
+                    thickness, paint, padding);
         }
 
         private void drawBeam(Canvas canvas, float left, float top, float right, float bottom,
@@ -253,8 +233,6 @@
                 mAlpha = (int) mAlphaOutAnimator.getAnimatedValue();
             } else if (animation == mAlphaInAnimator) {
                 mAlpha = (int) mAlphaInAnimator.getAnimatedValue();
-            } else if (animation == mTracingAnimator) {
-                mTracingProgress = (float) mTracingAnimator.getAnimatedValue();
             }
             invalidate();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
index 0549afa..65d6805 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooter.java
@@ -138,7 +138,7 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == DialogInterface.BUTTON_NEGATIVE) {
             final Intent settingsIntent = new Intent(ACTION_VPN_SETTINGS);
-            mContext.startActivityAsUser(settingsIntent, UserHandle.CURRENT);
+            mHost.startActivityDismissingKeyguard(settingsIntent);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index b38dd17..3d192e5 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -28,6 +28,8 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.service.quicksettings.TileService;
+import android.widget.Button;
+
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DrawableIcon;
@@ -109,6 +111,8 @@
         }
         TileInfo info = new TileInfo();
         info.state = state;
+        info.state.minimalAccessibilityClassName = info.state.expandedAccessibilityClassName =
+                Button.class.getName();
         info.spec = spec;
         info.appLabel = appLabel;
         info.isSystem = isSystem;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 9fb8bd5..2c5c437 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -34,6 +34,7 @@
 import android.util.Property;
 import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewGroup;
 import android.view.ViewParent;
 import android.view.ViewStub;
 
@@ -285,6 +286,26 @@
     }
 
     /**
+     * Returns whether this view, or one of its descendants have accessibility focus.
+     */
+    public static boolean isDescendentAccessibilityFocused(View v) {
+        if (v.isAccessibilityFocused()) {
+            return true;
+        }
+
+        if (v instanceof ViewGroup) {
+            ViewGroup vg = (ViewGroup) v;
+            int childCount = vg.getChildCount();
+            for (int i = 0; i < childCount; i++) {
+                if (isDescendentAccessibilityFocused(vg.getChildAt(i))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Returns the application configuration, which is independent of the activity's current
      * configuration in multiwindow.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index 72a589f..e757560 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -56,6 +56,7 @@
     private ImageView mBadgeView;
     private Task mTask;
     private boolean mDismissState;
+    private boolean mTouchExplorationEnabled;
     private int mCornerRadius;
 
     private ViewFocusAnimator mViewFocusAnimator;
@@ -90,7 +91,8 @@
                 R.dimen.recents_task_view_rounded_corners_radius);
         mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, mInfoFieldView);
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (!ssp.isTouchExplorationEnabled()) {
+        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+        if (!mTouchExplorationEnabled) {
             mDismissIconView.setVisibility(VISIBLE);
         } else {
             mDismissIconView.setVisibility(GONE);
@@ -237,10 +239,15 @@
     private void setDismissState(boolean dismissState) {
         if (mDismissState != dismissState) {
             mDismissState = dismissState;
-            if (dismissState) {
-                mDismissAnimationsHolder.startEnterAnimation();
-            } else {
-                mDismissAnimationsHolder.startExitAnimation();
+            // Check for touch exploration to ensure dismiss icon/text do not
+            // get animated. This should be removed based on decision from
+            // b/29208918
+            if (!mTouchExplorationEnabled) {
+                if (dismissState) {
+                    mDismissAnimationsHolder.startEnterAnimation();
+                } else {
+                    mDismissAnimationsHolder.startExitAnimation();
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 41869dd..e503c56 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -209,7 +209,9 @@
             EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
         } else {
             // Dismiss the task if we fail to launch it
-            taskView.dismissTask();
+            if (taskView != null) {
+                taskView.dismissTask();
+            }
 
             // Keep track of failed launches
             EventBus.getDefault().send(new LaunchTaskFailedEvent());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 231360e..586a8bc 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -44,6 +44,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
+import android.widget.ScrollView;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
@@ -170,7 +171,7 @@
     @ViewDebug.ExportedProperty(category="recents")
     private boolean mEnterAnimationComplete = false;
     @ViewDebug.ExportedProperty(category="recents")
-    private boolean mTouchExplorationEnabled;
+    boolean mTouchExplorationEnabled;
     @ViewDebug.ExportedProperty(category="recents")
     boolean mScreenPinningEnabled;
 
@@ -579,7 +580,7 @@
             if (task.isFreeformTask() || (transform != null && transform.visible)) {
                 mTmpTaskViewMap.put(task.key, tv);
             } else {
-                if (mTouchExplorationEnabled) {
+                if (mTouchExplorationEnabled && Utilities.isDescendentAccessibilityFocused(tv)) {
                     lastFocusedTaskIndex = taskIndex;
                     resetFocusedTask(task);
                 }
@@ -630,12 +631,14 @@
 
         // Update the focus if the previous focused task was returned to the view pool
         if (lastFocusedTaskIndex != -1) {
-            if (lastFocusedTaskIndex < visibleTaskRange[1]) {
-                setFocusedTask(visibleTaskRange[1], false /* scrollToTask */,
-                        true /* requestViewFocus */);
-            } else {
-                setFocusedTask(visibleTaskRange[0], false /* scrollToTask */,
-                        true /* requestViewFocus */);
+            int newFocusedTaskIndex = (lastFocusedTaskIndex < visibleTaskRange[1])
+                    ? visibleTaskRange[1]
+                    : visibleTaskRange[0];
+            setFocusedTask(newFocusedTaskIndex, false /* scrollToTask */,
+                    true /* requestViewFocus */);
+            TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
+            if (focusedTaskView != null) {
+                focusedTaskView.requestAccessibilityFocus();
             }
         }
     }
@@ -938,24 +941,7 @@
      *                            focus.
      */
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated) {
-        setRelativeFocusedTask(forward, stackTasksOnly, animated, false);
-    }
-
-    /**
-     * Sets the focused task relative to the currently focused task.
-     *
-     * @param forward whether to go to the next task in the stack (along the curve) or the previous
-     * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
-     *                       if the currently focused task is not a stack task, will set the focus
-     *                       to the first visible stack task
-     * @param animated determines whether to actually draw the highlight along with the change in
-     *                            focus.
-     * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
-     *                               happens.
-     */
-    public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
-                                       boolean cancelWindowAnimations) {
-        setRelativeFocusedTask(forward, stackTasksOnly, animated, cancelWindowAnimations, 0);
+        setRelativeFocusedTask(forward, stackTasksOnly, animated, false, 0);
     }
 
     /**
@@ -972,13 +958,13 @@
      * @param timerIndicatorDuration the duration to initialize the auto-advance timer indicator
      */
     public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
-                                       boolean cancelWindowAnimations,
-                                       int timerIndicatorDuration) {
-        int newIndex = mStack.indexOfStackTask(mFocusedTask);
-        if (mFocusedTask != null) {
+                                       boolean cancelWindowAnimations, int timerIndicatorDuration) {
+        Task focusedTask = getFocusedTask();
+        int newIndex = mStack.indexOfStackTask(focusedTask);
+        if (focusedTask != null) {
             if (stackTasksOnly) {
                 List<Task> tasks =  mStack.getStackTasks();
-                if (mFocusedTask.isFreeformTask()) {
+                if (focusedTask.isFreeformTask()) {
                     // Try and focus the front most stack task
                     TaskView tv = getFrontMostTaskView(stackTasksOnly);
                     if (tv != null) {
@@ -1054,6 +1040,25 @@
         return mFocusedTask;
     }
 
+    /**
+     * Returns the accessibility focused task.
+     */
+    Task getAccessibilityFocusedTask() {
+        List<TaskView> taskViews = getTaskViews();
+        int taskViewCount = taskViews.size();
+        for (int i = 0; i < taskViewCount; i++) {
+            TaskView tv = taskViews.get(i);
+            if (Utilities.isDescendentAccessibilityFocused(tv)) {
+                return tv.getTask();
+            }
+        }
+        TaskView frontTv = getFrontMostTaskView(true /* stackTasksOnly */);
+        if (frontTv != null) {
+            return frontTv.getTask();
+        }
+        return null;
+    }
+
     @Override
     public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
         super.onInitializeAccessibilityEvent(event);
@@ -1078,21 +1083,23 @@
         super.onInitializeAccessibilityNodeInfo(info);
         List<TaskView> taskViews = getTaskViews();
         int taskViewCount = taskViews.size();
-        if (taskViewCount > 1 && mFocusedTask != null) {
+        if (taskViewCount > 1) {
+            // Find the accessibility focused task
+            Task focusedTask = getAccessibilityFocusedTask();
             info.setScrollable(true);
-            int focusedTaskIndex = mStack.indexOfStackTask(mFocusedTask);
+            int focusedTaskIndex = mStack.indexOfStackTask(focusedTask);
             if (focusedTaskIndex > 0) {
-                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
-            }
-            if (focusedTaskIndex < mStack.getTaskCount() - 1) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
             }
+            if (0 <= focusedTaskIndex && focusedTaskIndex < mStack.getTaskCount() - 1) {
+                info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
+            }
         }
     }
 
     @Override
     public CharSequence getAccessibilityClassName() {
-        return TaskStackView.class.getName();
+        return ScrollView.class.getName();
     }
 
     @Override
@@ -1100,14 +1107,20 @@
         if (super.performAccessibilityAction(action, arguments)) {
             return true;
         }
-        switch (action) {
-            case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
-                setRelativeFocusedTask(true, false /* stackTasksOnly */, false /* animated */);
-                return true;
-            }
-            case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
-                setRelativeFocusedTask(false, false /* stackTasksOnly */, false /* animated */);
-                return true;
+        Task focusedTask = getAccessibilityFocusedTask();
+        int taskIndex = mStack.indexOfStackTask(focusedTask);
+        if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
+            switch (action) {
+                case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
+                    setFocusedTask(taskIndex + 1, true /* scrollToTask */, true /* requestViewFocus */,
+                            0);
+                    return true;
+                }
+                case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
+                    setFocusedTask(taskIndex - 1, true /* scrollToTask */, true /* requestViewFocus */,
+                            0);
+                    return true;
+                }
             }
         }
         return false;
@@ -1489,6 +1502,7 @@
         unbindTaskView(tv, task);
 
         // Reset the view properties and view state
+        tv.clearAccessibilityFocus();
         tv.resetViewProperties();
         tv.setFocusedState(false, false /* requestViewFocus */);
         tv.setClipViewInStack(false);
@@ -1949,6 +1963,10 @@
                         RecentsActivityLaunchState launchState = config.getLaunchState();
                         setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
                                 false /* scrollToTask */, launchState.launchedWithAltTab);
+                        TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
+                        if (mTouchExplorationEnabled && focusedTaskView != null) {
+                            focusedTaskView.requestAccessibilityFocus();
+                        }
                     }
 
                     EventBus.getDefault().send(new EnterRecentsTaskStackAnimationCompletedEvent());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index b554a46..67a2595 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -343,7 +343,9 @@
                     }
 
                     // Reset the focused task after the user has scrolled
-                    mSv.resetFocusedTask(mSv.getFocusedTask());
+                    if (!mSv.mTouchExplorationEnabled) {
+                        mSv.resetFocusedTask(mSv.getFocusedTask());
+                    }
                 } else if (mActiveTaskView == null) {
                     // This tap didn't start on a task.
                     maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY());
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 612c41d..4ecdd77 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -133,8 +133,6 @@
     @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
     private Task mTask;
     @ViewDebug.ExportedProperty(category="recents")
-    private boolean mTaskDataLoaded;
-    @ViewDebug.ExportedProperty(category="recents")
     private boolean mClipViewInStack = true;
     @ViewDebug.ExportedProperty(category="recents")
     private boolean mTouchExplorationEnabled;
@@ -451,16 +449,12 @@
      * Explicitly sets the focused state of this task.
      */
     public void setFocusedState(boolean isFocused, boolean requestViewFocus) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         if (isFocused) {
             if (requestViewFocus && !isFocused()) {
                 requestFocus();
             }
-            if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
-                requestAccessibilityFocus();
-            }
         } else {
-            if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) {
+            if (isAccessibilityFocused() && mTouchExplorationEnabled) {
                 clearAccessibilityFocus();
             }
         }
@@ -622,7 +616,6 @@
         // Update each of the views to the new task data
         mThumbnailView.onTaskDataLoaded(thumbnailInfo);
         mHeaderView.onTaskDataLoaded();
-        mTaskDataLoaded = true;
     }
 
     @Override
@@ -631,7 +624,6 @@
         mTask.removeCallback(this);
         mThumbnailView.unbindFromTask();
         mHeaderView.unbindFromTask(mTouchExplorationEnabled);
-        mTaskDataLoaded = false;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index aedc7df..28a6851 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -193,6 +193,13 @@
         mGroupExpansionChanging = changing;
     }
 
+    @Override
+    public void setActualHeightAnimating(boolean animating) {
+        if (mPrivateLayout != null) {
+            mPrivateLayout.setContentHeightAnimating(animating);
+        }
+    }
+
     public NotificationContentView getPrivateLayout() {
         return mPrivateLayout;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 2c302ed..b4f90c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -432,6 +432,8 @@
         return false;
     }
 
+    public void setActualHeightAnimating(boolean animating) {}
+
     /**
      * A listener notifying when {@link #getActualHeight} changes.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 21fed3c..a11263a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -106,13 +106,19 @@
     private boolean mExpandable;
     private boolean mClipToActualHeight = true;
     private ExpandableNotificationRow mContainingNotification;
+    /** The visible type at the start of a touch driven transformation */
     private int mTransformationStartVisibleType;
+    /** The visible type at the start of an animation driven transformation */
+    private int mAnimationStartVisibleType = UNDEFINED;
     private boolean mUserExpanding;
     private int mSingleLineWidthIndention;
     private boolean mForceSelectNextLayout = true;
     private PendingIntent mPreviousExpandedRemoteInputIntent;
     private PendingIntent mPreviousHeadsUpRemoteInputIntent;
 
+    private int mContentHeightAtAnimationStart = UNDEFINED;
+
+
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mHybridGroupManager = new HybridGroupManager(getContext(), this);
@@ -258,7 +264,14 @@
 
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+        int previousHeight = 0;
+        if (mExpandedChild != null) {
+            previousHeight = mExpandedChild.getHeight();
+        }
         super.onLayout(changed, left, top, right, bottom);
+        if (previousHeight != 0 && mExpandedChild.getHeight() != previousHeight) {
+            mContentHeightAtAnimationStart = previousHeight;
+        }
         updateClipping();
         invalidateOutline();
         selectLayout(false /* animate */, mForceSelectNextLayout /* force */);
@@ -408,24 +421,54 @@
      *         height, the notification is clipped instead of being further shrunk.
      */
     private int getMinContentHeightHint() {
-        if (mIsChildInGroup && (mVisibleType == VISIBLE_TYPE_SINGLELINE
-                || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE)) {
+        if (mIsChildInGroup && isVisibleOrTransitioning(VISIBLE_TYPE_SINGLELINE)) {
             return mContext.getResources().getDimensionPixelSize(
                         com.android.internal.R.dimen.notification_action_list_height);
         }
+
+        // Transition between heads-up & expanded, or pinned.
+        if (mHeadsUpChild != null && mExpandedChild != null) {
+            boolean transitioningBetweenHunAndExpanded =
+                    isTransitioningFromTo(VISIBLE_TYPE_HEADSUP, VISIBLE_TYPE_EXPANDED) ||
+                    isTransitioningFromTo(VISIBLE_TYPE_EXPANDED, VISIBLE_TYPE_HEADSUP);
+            boolean pinned = !isVisibleOrTransitioning(VISIBLE_TYPE_CONTRACTED) && mIsHeadsUp;
+            if (transitioningBetweenHunAndExpanded || pinned) {
+                return Math.min(mHeadsUpChild.getHeight(), mExpandedChild.getHeight());
+            }
+        }
+
+        // Size change of the expanded version
+        if ((mVisibleType == VISIBLE_TYPE_EXPANDED) && mContentHeightAtAnimationStart >= 0
+                && mExpandedChild != null) {
+            return Math.min(mContentHeightAtAnimationStart, mExpandedChild.getHeight());
+        }
+
         int hint;
-        if (mHeadsUpChild != null) {
+        if (mHeadsUpChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_HEADSUP)) {
             hint = mHeadsUpChild.getHeight();
+        } else if (mExpandedChild != null) {
+            hint = mExpandedChild.getHeight();
         } else {
             hint = mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
                     com.android.internal.R.dimen.notification_action_list_height);
         }
-        if (mExpandedChild != null) {
+
+        if (mExpandedChild != null && isVisibleOrTransitioning(VISIBLE_TYPE_EXPANDED)) {
             hint = Math.min(hint, mExpandedChild.getHeight());
         }
         return hint;
     }
 
+    private boolean isTransitioningFromTo(int from, int to) {
+        return (mTransformationStartVisibleType == from || mAnimationStartVisibleType == from)
+                && mVisibleType == to;
+    }
+
+    private boolean isVisibleOrTransitioning(int type) {
+        return mVisibleType == type || mTransformationStartVisibleType == type
+                || mAnimationStartVisibleType == type;
+    }
+
     private void updateContentTransformation() {
         int visibleType = calculateVisibleType();
         if (visibleType != mVisibleType) {
@@ -656,6 +699,7 @@
             shownView.setVisible(true);
             return;
         }
+        mAnimationStartVisibleType = mVisibleType;
         shownView.transformFrom(hiddenView);
         getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
         hiddenView.transformTo(shownView, new Runnable() {
@@ -664,6 +708,7 @@
                 if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
                     hiddenView.setVisible(false);
                 }
+                mAnimationStartVisibleType = UNDEFINED;
             }
         });
     }
@@ -1082,4 +1127,10 @@
             mHeadsUpRemoteInput.setRemoved();
         }
     }
+
+    public void setContentHeightAnimating(boolean animating) {
+        if (!animating) {
+            mContentHeightAtAnimationStart = UNDEFINED;
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java
index c0373be..8c72544 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActionListTransformState.java
@@ -44,6 +44,16 @@
     }
 
     @Override
+    public void transformViewFullyFrom(TransformState otherState, float transformationAmount) {
+        // Don't do Y transform - let the wrapper handle this based on the content height
+    }
+
+    @Override
+    public void transformViewFullyTo(TransformState otherState, float transformationAmount) {
+        // Don't do Y transform - let the wrapper handle this based on the content height
+    }
+
+    @Override
     protected void resetTransformedView() {
         // We need to keep the Y transformation, because this is used to keep the action list
         // aligned at the bottom, unrelated to transforms.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
new file mode 100644
index 0000000..ff2febf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification;
+
+import com.android.internal.widget.MessagingLinearLayout;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.TransformableView;
+
+import android.content.Context;
+import android.service.notification.StatusBarNotification;
+import android.view.View;
+
+/**
+ * Wraps a notification containing a messaging template
+ */
+public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
+
+    private View mContractedMessage;
+
+    protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
+        super(ctx, view, row);
+    }
+
+    private void resolveViews() {
+        mContractedMessage = null;
+
+        View container = mView.findViewById(com.android.internal.R.id.notification_messaging);
+        if (container instanceof MessagingLinearLayout
+                && ((MessagingLinearLayout) container).getChildCount() > 0) {
+            MessagingLinearLayout messagingContainer = (MessagingLinearLayout) container;
+
+            // Only consider the first child - transforming to a position other than the first
+            // looks bad because we have to move across other messages that are fading in.
+            View child = messagingContainer.getChildAt(0);
+            if (child.getId() == messagingContainer.getContractedChildId()) {
+                mContractedMessage = child;
+            }
+        }
+    }
+
+    @Override
+    public void notifyContentUpdated(StatusBarNotification notification) {
+        // Reinspect the notification. Before the super call, because the super call also updates
+        // the transformation types and we need to have our values set by then.
+        resolveViews();
+        super.notifyContentUpdated(notification);
+    }
+
+    @Override
+    protected void updateTransformedTypes() {
+        // This also clears the existing types
+        super.updateTransformedTypes();
+        if (mContractedMessage != null) {
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+                    mContractedMessage);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 22519e6..16348dfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -50,6 +50,8 @@
                 return new NotificationBigTextTemplateViewWrapper(ctx, v, row);
             } else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
                 return new NotificationMediaTemplateViewWrapper(ctx, v, row);
+            } else if ("messaging".equals(v.getTag())) {
+                return new NotificationMessagingTemplateViewWrapper(ctx, v, row);
             }
             return new NotificationTemplateViewWrapper(ctx, v, row);
         } else if (v instanceof NotificationHeaderView) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index 6d0fbb15..58fbd4c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -80,14 +80,16 @@
             new NightModeController.Listener() {
         @Override
         public void onNightModeChanged() {
-            mHost.addTile("night");
-            Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    mHost.getNightModeController().removeListener(mNightModeListener);
-                }
-            });
+            if (mHost.getNightModeController().isEnabled()) {
+                mHost.addTile("night");
+                Prefs.putBoolean(mContext, Key.QS_NIGHT_ADDED, true);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mHost.getNightModeController().removeListener(mNightModeListener);
+                    }
+                });
+            }
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
index 186005c..a92422a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DateView.java
@@ -21,7 +21,8 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.res.TypedArray;
-import android.text.format.DateFormat;
+import android.icu.text.DateFormat;
+import android.icu.text.DisplayContext;
 import android.util.AttributeSet;
 import android.widget.TextView;
 
@@ -36,7 +37,7 @@
 
     private final Date mCurrentTime = new Date();
 
-    private SimpleDateFormat mDateFormat;
+    private DateFormat mDateFormat;
     private String mLastText;
     private String mDatePattern;
 
@@ -100,8 +101,9 @@
     protected void updateClock() {
         if (mDateFormat == null) {
             final Locale l = Locale.getDefault();
-            final String fmt = DateFormat.getBestDateTimePattern(l, mDatePattern);
-            mDateFormat = new SimpleDateFormat(fmt, l);
+            DateFormat format = DateFormat.getInstanceForSkeleton(mDatePattern, l);
+            format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
+            mDateFormat = format;
         }
 
         mCurrentTime.setTime(System.currentTimeMillis());
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 0f94227..7ac0d80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -485,6 +485,7 @@
                 child.setTag(TAG_ANIMATOR_HEIGHT, null);
                 child.setTag(TAG_START_HEIGHT, null);
                 child.setTag(TAG_END_HEIGHT, null);
+                child.setActualHeightAnimating(false);
                 if (!mWasCancelled && child instanceof ExpandableNotificationRow) {
                     ((ExpandableNotificationRow) child).setGroupExpansionChanging(
                             false /* isExpansionChanging */);
@@ -505,6 +506,7 @@
         child.setTag(TAG_ANIMATOR_HEIGHT, animator);
         child.setTag(TAG_START_HEIGHT, child.getActualHeight());
         child.setTag(TAG_END_HEIGHT, newEndValue);
+        child.setActualHeightAnimating(true);
     }
 
     private void startInsetAnimation(final ExpandableView child,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index c6992aa..1973e05 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -977,6 +977,7 @@
             final int density = newConfig.densityDpi;
             if (density != mDensity) {
                 mDialog.dismiss();
+                mZenFooter.cleanup();
                 initDialog();
             }
             updateWindowWidthH();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
index 65975d9..f01e95f 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
@@ -79,18 +79,11 @@
         mZen = controller.getZen();
         mConfig = controller.getConfig();
         mController = controller;
+        mController.addCallback(mZenCallback);
         update();
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mController.addCallback(mZenCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
+    public void cleanup() {
         mController.removeCallback(mZenCallback);
     }
 
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 3d1370a..3333aa8 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -752,20 +752,12 @@
         rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
     }
 
-    native void rsnScriptReduce(long con, long id, int slot, long ain,
+    native void rsnScriptReduce(long con, long id, int slot, long[] ains,
                                 long aout, int[] limits);
-    synchronized void nScriptReduce(long id, int slot, long ain, long aout,
+    synchronized void nScriptReduce(long id, int slot, long ains[], long aout,
                                     int[] limits) {
         validate();
-        rsnScriptReduce(mContext, id, slot, ain, aout, limits);
-    }
-
-    native void rsnScriptReduceNew(long con, long id, int slot, long[] ains,
-                                   long aout, int[] limits);
-    synchronized void nScriptReduceNew(long id, int slot, long ains[], long aout,
-                                       int[] limits) {
-        validate();
-        rsnScriptReduceNew(mContext, id, slot, ains, aout, limits);
+        rsnScriptReduce(mContext, id, slot, ains, aout, limits);
     }
 
     native void rsnScriptInvokeV(long con, long id, int slot, byte[] params);
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index fc3280b..13d5fcd 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -286,35 +286,6 @@
     }
 
     /**
-     * Only intended for use by generated reflected code.  (Simple reduction)
-     *
-     * @hide
-     */
-    protected void reduce(int slot, Allocation ain, Allocation aout, LaunchOptions sc) {
-        mRS.validate();
-        mRS.validateObject(ain);
-        mRS.validateObject(aout);
-
-        if (ain == null || aout == null) {
-            throw new RSIllegalArgumentException(
-                "Both ain and aout are required to be non-null.");
-        }
-
-        long in_id = ain.getID(mRS);
-        long out_id = aout.getID(mRS);
-
-        int[] limits = null;
-        if (sc != null) {
-            limits = new int[2];
-
-            limits[0] = sc.xstart;
-            limits[1] = sc.xend;
-        }
-
-        mRS.nScriptReduce(getID(mRS), slot, in_id, out_id, limits);
-    }
-
-    /**
      * Only intended for use by generated reflected code.  (General reduction)
      *
      */
@@ -350,7 +321,7 @@
             limits[5] = sc.zend;
         }
 
-        mRS.nScriptReduceNew(getID(mRS), slot, in_ids, out_id, limits);
+        mRS.nScriptReduce(getID(mRS), slot, in_ids, out_id, limits);
     }
 
     long[] mInIdsBuffer;
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index e0f5934..aa2a607 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -2094,67 +2094,10 @@
 
 static void
 nScriptReduce(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-              jlong ain, jlong aout, jintArray limits)
+              jlongArray ains, jlong aout, jintArray limits)
 {
     if (kLogApi) {
-        ALOGD("nScriptReduce, con(%p), s(%p), slot(%i) ain(%" PRId64 ") aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ain, aout);
-    }
-
-    RsScriptCall sc, *sca = nullptr;
-    uint32_t sc_size = 0;
-
-    jint  limit_len = 0;
-    jint *limit_ptr = nullptr;
-
-    // If the caller passed limits, reflect them in the RsScriptCall.
-    if (limits != nullptr) {
-        limit_len = _env->GetArrayLength(limits);
-        limit_ptr = _env->GetIntArrayElements(limits, nullptr);
-        if (limit_ptr == nullptr) {
-            ALOGE("Failed to get Java array elements");
-            return;
-        }
-
-        // We expect to be passed an array [x1, x2] which specifies
-        // the sub-range for a 1-dimensional reduction.
-        assert(limit_len == 2);
-        UNUSED(limit_len);  // As the assert might not be compiled.
-
-        sc.xStart     = limit_ptr[0];
-        sc.xEnd       = limit_ptr[1];
-        sc.yStart     = 0;
-        sc.yEnd       = 0;
-        sc.zStart     = 0;
-        sc.zEnd       = 0;
-        sc.strategy   = RS_FOR_EACH_STRATEGY_DONT_CARE;
-        sc.arrayStart = 0;
-        sc.arrayEnd = 0;
-        sc.array2Start = 0;
-        sc.array2End = 0;
-        sc.array3Start = 0;
-        sc.array3End = 0;
-        sc.array4Start = 0;
-        sc.array4End = 0;
-
-        sca = &sc;
-        sc_size = sizeof(sc);
-    }
-
-    rsScriptReduce((RsContext)con, (RsScript)script, slot,
-                   (RsAllocation)ain, (RsAllocation)aout,
-                   sca, sc_size);
-
-    if (limits != nullptr) {
-        _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
-    }
-}
-
-static void
-nScriptReduceNew(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
-                 jlongArray ains, jlong aout, jintArray limits)
-{
-    if (kLogApi) {
-        ALOGD("nScriptReduceNew, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
+        ALOGD("nScriptReduce, con(%p), s(%p), slot(%i) ains(%p) aout(%" PRId64 ")", (RsContext)con, (void *)script, slot, ains, aout);
     }
 
     if (ains == nullptr) {
@@ -2233,9 +2176,9 @@
         sc_size = sizeof(sc);
     }
 
-    rsScriptReduceNew((RsContext)con, (RsScript)script, slot,
-                      in_allocs, in_len, (RsAllocation)aout,
-                      sca, sc_size);
+    rsScriptReduce((RsContext)con, (RsScript)script, slot,
+                   in_allocs, in_len, (RsAllocation)aout,
+                   sca, sc_size);
 
     _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
 
@@ -2951,8 +2894,7 @@
 {"rsnScriptInvokeV",                 "(JJI[B)V",                              (void*)nScriptInvokeV },
 
 {"rsnScriptForEach",                 "(JJI[JJ[B[I)V",                         (void*)nScriptForEach },
-{"rsnScriptReduce",                  "(JJIJJ[I)V",                            (void*)nScriptReduce },
-{"rsnScriptReduceNew",               "(JJI[JJ[I)V",                           (void*)nScriptReduceNew },
+{"rsnScriptReduce",                  "(JJI[JJ[I)V",                           (void*)nScriptReduce },
 
 {"rsnScriptSetVarI",                 "(JJII)V",                               (void*)nScriptSetVarI },
 {"rsnScriptGetVarI",                 "(JJI)I",                                (void*)nScriptGetVarI },
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index acc2ec3..334b228 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -9849,7 +9849,11 @@
 
         synchronized(this) {
             if (mActiveRestoreSession != null) {
-                Slog.d(TAG, "Restore session requested but one already active");
+                Slog.i(TAG, "Restore session requested but one already active");
+                return null;
+            }
+            if (mBackupRunning) {
+                Slog.i(TAG, "Restore session requested but currently running backups");
                 return null;
             }
             mActiveRestoreSession = new ActiveRestoreSession(packageName, transport);
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 8ad6e6a..400c4a7 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3073,9 +3073,14 @@
                 fs.numWakeup++;
                 if (alarm.workSource != null && alarm.workSource.size() > 0) {
                     for (int wi=0; wi<alarm.workSource.size(); wi++) {
+                        final String wsName = alarm.workSource.getName(wi);
+                        if (wsName == null) {
+                            Slog.w(TAG, "Null worksource name for alarm " + alarm);
+                        }
                         ActivityManagerNative.noteWakeupAlarm(
                                 alarm.operation, alarm.workSource.get(wi),
-                                alarm.workSource.getName(wi), alarm.statsTag);
+                                (wsName != null) ? wsName : alarm.packageName,
+                                alarm.statsTag);
                     }
                 } else {
                     ActivityManagerNative.noteWakeupAlarm(
diff --git a/services/core/java/com/android/server/AnyMotionDetector.java b/services/core/java/com/android/server/AnyMotionDetector.java
index e98b4aa..a8ae914d 100644
--- a/services/core/java/com/android/server/AnyMotionDetector.java
+++ b/services/core/java/com/android/server/AnyMotionDetector.java
@@ -308,7 +308,7 @@
     /**
      * A timestamped three dimensional vector and some vector operations.
      */
-    private static class Vector3 {
+    public static final class Vector3 {
         public long timeMillisSinceBoot;
         public float x;
         public float y;
@@ -321,11 +321,11 @@
             this.z = z;
         }
 
-        private float norm() {
+        public float norm() {
             return (float) Math.sqrt(dotProduct(this));
         }
 
-        private Vector3 normalized() {
+        public Vector3 normalized() {
             float mag = norm();
             return new Vector3(timeMillisSinceBoot, x / mag, y / mag, z / mag);
         }
@@ -338,12 +338,20 @@
          * @return angle between this vector and the other given one.
          */
         public float angleBetween(Vector3 other) {
-            double degrees = Math.toDegrees(Math.acos(this.dotProduct(other)));
-            float returnValue = (float) degrees;
+            Vector3 crossVector = cross(other);
+            float degrees = Math.abs((float)Math.toDegrees(
+                    Math.atan2(crossVector.norm(), dotProduct(other))));
             Slog.d(TAG, "angleBetween: this = " + this.toString() +
-                    ", other = " + other.toString());
-            Slog.d(TAG, "    degrees = " + degrees + ", returnValue = " + returnValue);
-            return returnValue;
+                ", other = " + other.toString() + ", degrees = " + degrees);
+            return degrees;
+        }
+
+        public Vector3 cross(Vector3 v) {
+            return new Vector3(
+                v.timeMillisSinceBoot,
+                y * v.z - z * v.y,
+                z * v.x - x * v.z,
+                x * v.y - y * v.x);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1adefc4..be440ed 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3566,14 +3566,14 @@
                     .build();
 
             try {
-                notificationManager.notify(NOTIFICATION_ID, id, notification);
+                notificationManager.notifyAsUser(NOTIFICATION_ID, id, notification, UserHandle.ALL);
             } catch (NullPointerException npe) {
                 loge("setNotificationVisible: visible notificationManager npe=" + npe);
                 npe.printStackTrace();
             }
         } else {
             try {
-                notificationManager.cancel(NOTIFICATION_ID, id);
+                notificationManager.cancelAsUser(NOTIFICATION_ID, id, UserHandle.ALL);
             } catch (NullPointerException npe) {
                 loge("setNotificationVisible: cancel notificationManager npe=" + npe);
                 npe.printStackTrace();
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e0b4960..36ec2eb 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -1431,6 +1431,13 @@
                 for (UpdateRecord record : records) {
                     if (isCurrentProfile(UserHandle.getUserId(record.mReceiver.mUid))) {
                         LocationRequest locationRequest = record.mRequest;
+
+                        // Don't assign battery blame for update records whose
+                        // client has no permission to receive location data.
+                        if (!providerRequest.locationRequests.contains(locationRequest)) {
+                            continue;
+                        }
+
                         if (locationRequest.getInterval() <= thresholdInterval) {
                             if (record.mReceiver.mWorkSource != null
                                     && record.mReceiver.mWorkSource.size() > 0
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index c89b6ea..9c75a00 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -3031,7 +3031,8 @@
                 if (forWrite) {
                     match = vol.isVisibleForWrite(userId);
                 } else {
-                    match = vol.isVisibleForRead(userId) || includeInvisible;
+                    match = vol.isVisibleForRead(userId)
+                            || (includeInvisible && vol.getPath() != null);
                 }
                 if (!match) continue;
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5cb4f71..63f122b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5375,17 +5375,18 @@
         userId = mUserController.handleIncomingUser(pid, uid, userId, false,
                 ALLOW_FULL_ONLY, "clearApplicationUserData", null);
 
-        final DevicePolicyManagerInternal dpmi = LocalServices
-                .getService(DevicePolicyManagerInternal.class);
-        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
-            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
-        }
 
         long callingId = Binder.clearCallingIdentity();
         try {
             IPackageManager pm = AppGlobals.getPackageManager();
             int pkgUid = -1;
             synchronized(this) {
+                if (getPackageManagerInternalLocked().canPackageBeWiped(
+                        userId, packageName)) {
+                    throw new SecurityException(
+                            "Cannot clear data for a device owner or a profile owner");
+                }
+
                 try {
                     pkgUid = pm.getPackageUid(packageName, MATCH_UNINSTALLED_PACKAGES, userId);
                 } catch (RemoteException e) {
@@ -6036,7 +6037,7 @@
         if (appId < 0 && packageName != null) {
             try {
                 appId = UserHandle.getAppId(AppGlobals.getPackageManager()
-                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId));
+                        .getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, 0));
             } catch (RemoteException e) {
             }
         }
@@ -13881,7 +13882,12 @@
                             args.length - opti);
                 }
                 synchronized (this) {
-                    dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+                    if (dumpCheckinFormat) {
+                        dumpBroadcastStatsCheckinLocked(fd, pw, args, opti, dumpCheckin,
+                                dumpPackage);
+                    } else {
+                        dumpBroadcastStatsLocked(fd, pw, args, opti, true, dumpPackage);
+                    }
                 }
             } else if ("intents".equals(cmd) || "i".equals(cmd)) {
                 String[] newArgs;
@@ -17778,6 +17784,11 @@
                                 getPackageManagerInternalLocked().getApplicationInfo(
                                         ssp,
                                         userId);
+                        if (aInfo == null) {
+                            Slog.w(TAG, "Dropping ACTION_PACKAGE_REPLACED for non-existent pkg:"
+                                    + " ssp=" + ssp + " data=" + data);
+                            return ActivityManager.BROADCAST_SUCCESS;
+                        }
                         mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
                         sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
                                 new String[] {ssp}, userId);
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1d1dc2b..7ddd59d 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1099,21 +1099,7 @@
             // Don't debug things in the system process
             if (!aInfo.processName.equals("system")) {
                 if ((startFlags & ActivityManager.START_FLAG_DEBUG) != 0) {
-                    final ProcessRecord app = mService.getProcessRecordLocked(
-                            aInfo.processName, aInfo.applicationInfo.uid, true);
-                    // If the process already started, we can't wait for debugger and shouldn't
-                    // modify the debug settings.
-                    // For non-persistent debug, normally we set the debug app here, and restores
-                    // to the original at attachApplication time. However, if the app process
-                    // already exists, we won't get another attachApplication, and the debug setting
-                    // never gets restored. Furthermore, if we get two such calls back-to-back,
-                    // both mOrigDebugApp and mDebugApp will become the same app, and it won't be
-                    // cleared even if we get attachApplication after the app process is killed.
-                    if (app == null || app.thread == null) {
-                        mService.setDebugApp(aInfo.processName, true, false);
-                    } else {
-                        Slog.w(TAG, "Ignoring waitForDebugger because process already exists");
-                    }
+                    mService.setDebugApp(aInfo.processName, true, false);
                 }
 
                 if ((startFlags & ActivityManager.START_FLAG_NATIVE_DEBUGGING) != 0) {
diff --git a/services/core/java/com/android/server/am/ActivityStartInterceptor.java b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
index 566d8d9..a2c2040 100644
--- a/services/core/java/com/android/server/am/ActivityStartInterceptor.java
+++ b/services/core/java/com/android/server/am/ActivityStartInterceptor.java
@@ -147,6 +147,9 @@
         }
         DevicePolicyManagerInternal devicePolicyManager = LocalServices.getService(
                 DevicePolicyManagerInternal.class);
+        if (devicePolicyManager == null) {
+            return false;
+        }
         mIntent = devicePolicyManager.createPackageSuspendedDialogIntent(
                 mAInfo.packageName, mUserId);
         mCallingPid = mRealCallingPid;
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index cea76f2..ab5d4b6 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -621,6 +621,9 @@
         for (int i = 0; i < recentsCount; i++) {
             final TaskRecord tr = get(i);
             if (task != tr) {
+                if (task.stack != tr.stack) {
+                    continue;
+                }
                 if (task.userId != tr.userId) {
                     continue;
                 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 4a0e81b..bef48d6 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -81,8 +81,6 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
 
 
@@ -126,7 +124,18 @@
     private final INetworkStatsService mStatsService;
     private final Looper mLooper;
 
-    private Map<String, TetherInterfaceStateMachine> mIfaces; // all tethered/tetherable ifaces
+    private static class TetherState {
+        public final TetherInterfaceStateMachine mStateMachine;
+        public int mLastState;
+        public int mLastError;
+        public TetherState(TetherInterfaceStateMachine sm) {
+            mStateMachine = sm;
+            // Assume all state machines start out available and with no errors.
+            mLastState = IControlsTethering.STATE_AVAILABLE;
+            mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+        }
+    }
+    private final ArrayMap<String, TetherState> mTetherStates;
 
     private final BroadcastReceiver mStateReceiver;
 
@@ -174,7 +183,7 @@
 
         mPublicSync = new Object();
 
-        mIfaces = new ArrayMap<String, TetherInterfaceStateMachine>();
+        mTetherStates = new ArrayMap<>();
 
         // make our own thread so we don't anr the system
         mLooper = IoThread.get().getLooper();
@@ -255,22 +264,20 @@
                 return;
             }
 
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
+            TetherState tetherState = mTetherStates.get(iface);
             if (up) {
-                if (sm == null) {
-                    sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType,
-                            mNMService, mStatsService, this);
-                    mIfaces.put(iface, sm);
-                    sm.start();
+                if (tetherState == null) {
+                    trackNewTetherableInterface(iface, interfaceType);
                 }
             } else {
                 if (interfaceType == ConnectivityManager.TETHERING_USB) {
                     // ignore usb0 down after enabling RNDIS
                     // we will handle disconnect in interfaceRemoved instead
                     if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
-                } else if (sm != null) {
-                    sm.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-                    mIfaces.remove(iface);
+                } else if (tetherState != null) {
+                    tetherState.mStateMachine.sendMessage(
+                            TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
+                    mTetherStates.remove(iface);
                 }
             }
         }
@@ -329,15 +336,12 @@
                 return;
             }
 
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
-            if (sm != null) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
+                trackNewTetherableInterface(iface, interfaceType);
+            } else {
                 if (VDBG) Log.d(TAG, "active iface (" + iface + ") reported as added, ignoring");
-                return;
             }
-            sm = new TetherInterfaceStateMachine(iface, mLooper, interfaceType,
-                    mNMService, mStatsService, this);
-            mIfaces.put(iface, sm);
-            sm.start();
         }
     }
 
@@ -345,15 +349,15 @@
     public void interfaceRemoved(String iface) {
         if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
         synchronized (mPublicSync) {
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
-            if (sm == null) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
                 if (VDBG) {
                     Log.e(TAG, "attempting to remove unknown iface (" + iface + "), ignoring");
                 }
                 return;
             }
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            mIfaces.remove(iface);
+            tetherState.mStateMachine.sendMessage(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
+            mTetherStates.remove(iface);
         }
     }
 
@@ -582,19 +586,18 @@
     public int tether(String iface) {
         if (DBG) Log.d(TAG, "Tethering " + iface);
         synchronized (mPublicSync) {
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
-            if (sm == null) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
                 Log.e(TAG, "Tried to Tether an unknown iface :" + iface + ", ignoring");
                 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
             }
             // Ignore the error status of the interface.  If the interface is available,
             // the errors are referring to past tethering attempts anyway.
-            if (!sm.isAvailable()) {
+            if (tetherState.mLastState != IControlsTethering.STATE_AVAILABLE) {
                 Log.e(TAG, "Tried to Tether an unavailable iface :" + iface + ", ignoring");
                 return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
-
             }
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
+            tetherState.mStateMachine.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
             return ConnectivityManager.TETHER_ERROR_NO_ERROR;
         }
     }
@@ -602,43 +605,43 @@
     public int untether(String iface) {
         if (DBG) Log.d(TAG, "Untethering " + iface);
         synchronized (mPublicSync) {
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
-            if (sm == null) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
                 Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
                 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
             }
-            if (!sm.isTethered()) {
-                Log.e(TAG, "Tried to Untethered an errored iface :" + iface + ", ignoring");
+            if (tetherState.mLastState != IControlsTethering.STATE_TETHERED) {
+                Log.e(TAG, "Tried to untether an untethered iface :" + iface + ", ignoring");
                 return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
             }
-            sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
+            tetherState.mStateMachine.sendMessage(
+                    TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
             return ConnectivityManager.TETHER_ERROR_NO_ERROR;
         }
     }
 
     public void untetherAll() {
-        if (DBG) Log.d(TAG, "Untethering " + mIfaces);
-        for (String iface : mIfaces.keySet()) {
-            untether(iface);
+        synchronized (mPublicSync) {
+            if (DBG) Log.d(TAG, "Untethering " + mTetherStates.keySet());
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                untether(mTetherStates.keyAt(i));
+            }
         }
     }
 
     public int getLastTetherError(String iface) {
         synchronized (mPublicSync) {
-            TetherInterfaceStateMachine sm = mIfaces.get(iface);
-            if (sm == null) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState == null) {
                 Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
                         ", ignoring");
                 return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
             }
-            return sm.getLastError();
+            return tetherState.mLastError;
         }
     }
 
-    // TODO - move all private methods used only by the state machine into the state machine
-    // to clarify what needs synchronized protection.
-    @Override
-    public void sendTetherStateChangedBroadcast() {
+    private void sendTetherStateChangedBroadcast() {
         if (!getConnectivityManager().isTetheringSupported()) return;
 
         ArrayList<String> availableList = new ArrayList<String>();
@@ -650,24 +653,22 @@
         boolean bluetoothTethered = false;
 
         synchronized (mPublicSync) {
-            Set<String> ifaces = mIfaces.keySet();
-            for (String iface : ifaces) {
-                TetherInterfaceStateMachine sm = mIfaces.get(iface);
-                if (sm != null) {
-                    if (sm.isErrored()) {
-                        erroredList.add(iface);
-                    } else if (sm.isAvailable()) {
-                        availableList.add(iface);
-                    } else if (sm.isTethered()) {
-                        if (isUsb(iface)) {
-                            usbTethered = true;
-                        } else if (isWifi(iface)) {
-                            wifiTethered = true;
-                      } else if (isBluetooth(iface)) {
-                            bluetoothTethered = true;
-                        }
-                        activeList.add(iface);
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                String iface = mTetherStates.keyAt(i);
+                if (tetherState.mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                    erroredList.add(iface);
+                } else if (tetherState.mLastState == IControlsTethering.STATE_AVAILABLE) {
+                    availableList.add(iface);
+                } else if (tetherState.mLastState == IControlsTethering.STATE_TETHERED) {
+                    if (isUsb(iface)) {
+                        usbTethered = true;
+                    } else if (isWifi(iface)) {
+                        wifiTethered = true;
+                    } else if (isBluetooth(iface)) {
+                        bluetoothTethered = true;
                     }
+                    activeList.add(iface);
                 }
             }
         }
@@ -961,37 +962,27 @@
     public String[] getTetheredIfaces() {
         ArrayList<String> list = new ArrayList<String>();
         synchronized (mPublicSync) {
-            Set<String> keys = mIfaces.keySet();
-            for (String key : keys) {
-                TetherInterfaceStateMachine sm = mIfaces.get(key);
-                if (sm.isTethered()) {
-                    list.add(key);
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.mLastState == IControlsTethering.STATE_TETHERED) {
+                    list.add(mTetherStates.keyAt(i));
                 }
             }
         }
-        String[] retVal = new String[list.size()];
-        for (int i=0; i < list.size(); i++) {
-            retVal[i] = list.get(i);
-        }
-        return retVal;
+        return list.toArray(new String[list.size()]);
     }
 
     public String[] getTetherableIfaces() {
         ArrayList<String> list = new ArrayList<String>();
         synchronized (mPublicSync) {
-            Set<String> keys = mIfaces.keySet();
-            for (String key : keys) {
-                TetherInterfaceStateMachine sm = mIfaces.get(key);
-                if (sm.isAvailable()) {
-                    list.add(key);
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.mLastState == IControlsTethering.STATE_AVAILABLE) {
+                    list.add(mTetherStates.keyAt(i));
                 }
             }
         }
-        String[] retVal = new String[list.size()];
-        for (int i=0; i < list.size(); i++) {
-            retVal[i] = list.get(i);
-        }
-        return retVal;
+        return list.toArray(new String[list.size()]);
     }
 
     public String[] getTetheredDhcpRanges() {
@@ -1001,19 +992,14 @@
     public String[] getErroredIfaces() {
         ArrayList<String> list = new ArrayList<String>();
         synchronized (mPublicSync) {
-            Set<String> keys = mIfaces.keySet();
-            for (String key : keys) {
-                TetherInterfaceStateMachine sm = mIfaces.get(key);
-                if (sm.isErrored()) {
-                    list.add(key);
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                TetherState tetherState = mTetherStates.valueAt(i);
+                if (tetherState.mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                    list.add(mTetherStates.keyAt(i));
                 }
             }
         }
-        String[] retVal = new String[list.size()];
-        for (int i= 0; i< list.size(); i++) {
-            retVal[i] = list.get(i);
-        }
-        return retVal;
+        return list.toArray(new String[list.size()]);
     }
 
     private void maybeLogMessage(State state, int what) {
@@ -1143,6 +1129,18 @@
         private State mStopTetheringErrorState;
         private State mSetDnsForwardersErrorState;
 
+        // This list is a little subtle.  It contains all the interfaces that currently are
+        // requesting tethering, regardless of whether these interfaces are still members of
+        // mTetherStates.  This allows us to maintain the following predicates:
+        //
+        // 1) mTetherStates contains the set of all currently existing, tetherable, link state up
+        //    interfaces.
+        // 2) mNotifyList contains all state machines that may have outstanding tethering state
+        //    that needs to be torn down.
+        //
+        // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
+        // so that the garbage collector does not clean up the state machine before it has a chance
+        // to tear itself down.
         private ArrayList<TetherInterfaceStateMachine> mNotifyList;
 
         private int mMobileApnReserved = ConnectivityManager.TYPE_NONE;
@@ -1453,15 +1451,16 @@
                                 config_mobile_hotspot_provision_app_no_ui).isEmpty() == false) {
                             ArrayList<Integer> tethered = new ArrayList<Integer>();
                             synchronized (mPublicSync) {
-                                Set<String> ifaces = mIfaces.keySet();
-                                for (String iface : ifaces) {
-                                    TetherInterfaceStateMachine sm = mIfaces.get(iface);
-                                    if (sm != null && sm.isTethered()) {
-                                        int interfaceType = ifaceNameToType(iface);
-                                        if (interfaceType !=
-                                                ConnectivityManager.TETHERING_INVALID) {
-                                            tethered.add(new Integer(interfaceType));
-                                        }
+                                for (int i = 0; i < mTetherStates.size(); i++) {
+                                    TetherState tetherState = mTetherStates.valueAt(i);
+                                    if (tetherState.mLastState !=
+                                            IControlsTethering.STATE_TETHERED) {
+                                        continue;  // Skip interfaces that aren't tethered.
+                                    }
+                                    String iface = mTetherStates.keyAt(i);
+                                    int interfaceType = ifaceNameToType(iface);
+                                    if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
+                                        tethered.add(new Integer(interfaceType));
                                     }
                                 }
                             }
@@ -1488,9 +1487,6 @@
 
         class InitialState extends TetherMasterUtilState {
             @Override
-            public void enter() {
-            }
-            @Override
             public boolean processMessage(Message message) {
                 maybeLogMessage(this, message.what);
                 boolean retValue = true;
@@ -1498,16 +1494,15 @@
                     case CMD_TETHER_MODE_REQUESTED:
                         TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
-                        mNotifyList.add(who);
+                        if (mNotifyList.indexOf(who) < 0) {
+                            mNotifyList.add(who);
+                        }
                         transitionTo(mTetherModeAliveState);
                         break;
                     case CMD_TETHER_MODE_UNREQUESTED:
                         who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
-                        int index = mNotifyList.indexOf(who);
-                        if (index != -1) {
-                            mNotifyList.remove(who);
-                        }
+                        mNotifyList.remove(who);
                         break;
                     default:
                         retValue = false;
@@ -1546,24 +1541,26 @@
                     case CMD_TETHER_MODE_REQUESTED:
                         TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
-                        mNotifyList.add(who);
+                        if (mNotifyList.indexOf(who) < 0) {
+                            mNotifyList.add(who);
+                        }
                         who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
                                 mCurrentUpstreamIface);
                         break;
                     case CMD_TETHER_MODE_UNREQUESTED:
                         who = (TetherInterfaceStateMachine)message.obj;
                         if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
-                        int index = mNotifyList.indexOf(who);
-                        if (index != -1) {
+                        if (mNotifyList.remove(who)) {
                             if (DBG) Log.d(TAG, "TetherModeAlive removing notifyee " + who);
-                            mNotifyList.remove(index);
                             if (mNotifyList.isEmpty()) {
                                 turnOffMasterTetherSettings(); // transitions appropriately
                             } else {
                                 if (DBG) {
                                     Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size() +
                                             " live requests:");
-                                    for (Object o : mNotifyList) Log.d(TAG, "  " + o);
+                                    for (TetherInterfaceStateMachine o : mNotifyList) {
+                                        Log.d(TAG, "  " + o);
+                                    }
                                 }
                             }
                         } else {
@@ -1623,8 +1620,7 @@
             }
             void notify(int msgType) {
                 mErrorNotification = msgType;
-                for (Object o : mNotifyList) {
-                    TetherInterfaceStateMachine sm = (TetherInterfaceStateMachine)o;
+                for (TetherInterfaceStateMachine sm : mNotifyList) {
                     sm.sendMessage(msgType);
                 }
             }
@@ -1707,8 +1703,26 @@
 
             pw.println("Tether state:");
             pw.increaseIndent();
-            for (Object o : mIfaces.values()) {
-                pw.println(o);
+            for (int i = 0; i < mTetherStates.size(); i++) {
+                final String iface = mTetherStates.keyAt(i);
+                final TetherState tetherState = mTetherStates.valueAt(i);
+                pw.print(iface + " - ");
+
+                switch (tetherState.mLastState) {
+                    case IControlsTethering.STATE_UNAVAILABLE:
+                        pw.print("UnavailableState");
+                        break;
+                    case IControlsTethering.STATE_AVAILABLE:
+                        pw.print("AvailableState");
+                        break;
+                    case IControlsTethering.STATE_TETHERED:
+                        pw.print("TetheredState");
+                        break;
+                    default:
+                        pw.print("UnknownState");
+                        break;
+                }
+                pw.println(" - lastError = " + tetherState.mLastError);
             }
             pw.decreaseIndent();
         }
@@ -1716,9 +1730,40 @@
     }
 
     @Override
-    public void notifyInterfaceTetheringReadiness(boolean isReady,
-            TetherInterfaceStateMachine who) {
-        mTetherMasterSM.sendMessage((isReady) ? TetherMasterSM.CMD_TETHER_MODE_REQUESTED
-                                              : TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, who);
+    public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
+                                           int state, int error) {
+        synchronized (mPublicSync) {
+            TetherState tetherState = mTetherStates.get(iface);
+            if (tetherState != null && tetherState.mStateMachine.equals(who)) {
+                tetherState.mLastState = state;
+                tetherState.mLastError = error;
+            } else {
+                if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
+            }
+        }
+
+        if (DBG) {
+            Log.d(TAG, "iface " + iface + " notified that it was in state " + state +
+                    " with error " + error);
+        }
+
+        switch (state) {
+            case IControlsTethering.STATE_UNAVAILABLE:
+            case IControlsTethering.STATE_AVAILABLE:
+                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_UNREQUESTED, who);
+                break;
+            case IControlsTethering.STATE_TETHERED:
+                mTetherMasterSM.sendMessage(TetherMasterSM.CMD_TETHER_MODE_REQUESTED, who);
+                break;
+        }
+        sendTetherStateChangedBroadcast();
+    }
+
+    private void trackNewTetherableInterface(String iface, int interfaceType) {
+        TetherState tetherState;
+        tetherState = new TetherState(new TetherInterfaceStateMachine(iface, mLooper,
+                interfaceType, mNMService, mStatsService, this));
+        mTetherStates.put(iface, tetherState);
+        tetherState.mStateMachine.start();
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
index 7677daf..449b8a8 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
@@ -22,6 +22,18 @@
  * Interface with methods necessary to notify that a given interface is ready for tethering.
  */
 public interface IControlsTethering {
-    void sendTetherStateChangedBroadcast();
-    void notifyInterfaceTetheringReadiness(boolean isReady, TetherInterfaceStateMachine who);
+    public final int STATE_UNAVAILABLE = 0;
+    public final int STATE_AVAILABLE = 1;
+    public final int STATE_TETHERED = 2;
+
+    /**
+     * Notify that |who| has changed its tethering state.  This may be called from any thread.
+     *
+     * @param iface a network interface (e.g. "wlan0")
+     * @param who corresponding instance of a TetherInterfaceStateMachine
+     * @param state one of IControlsTethering.STATE_*
+     * @param lastError one of ConnectivityManager.TETHER_ERROR_*
+     */
+    void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
+                                    int state, int lastError);
 }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index b8bea60..aebeb69 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -27,7 +27,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.internal.util.IState;
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
@@ -98,7 +97,7 @@
         mTetherController = tetherController;
         mIfaceName = ifaceName;
         mInterfaceType = interfaceType;
-        setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
+        mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
 
         mInitialState = new InitialState();
         addState(mInitialState);
@@ -110,40 +109,6 @@
         setInitialState(mInitialState);
     }
 
-    @Override
-    public String toString() {
-        String res = new String();
-        res += mIfaceName + " - ";
-        IState current = getCurrentState();
-        if (current == mInitialState) res += "InitialState";
-        if (current == mTetheredState) res += "TetheredState";
-        if (current == mUnavailableState) res += "UnavailableState";
-        if (isAvailable()) res += " - Available";
-        if (isTethered()) res += " - Tethered";
-        res += " - lastError =" + getLastError();
-        return res;
-    }
-
-    public int getLastError() {
-        return mLastError;
-    }
-
-    private void setLastError(int error) {
-        mLastError = error;
-    }
-
-    public boolean isAvailable() {
-        return getCurrentState() == mInitialState;
-    }
-
-    public boolean isTethered() {
-        return getCurrentState() == mTetheredState;
-    }
-
-    public boolean isErrored() {
-        return (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR);
-    }
-
     // configured when we start tethering and unconfig'd on error or conclusion
     private boolean configureIfaceIp(boolean enabled) {
         if (VDBG) Log.d(TAG, "configureIfaceIp(" + enabled + ")");
@@ -193,7 +158,9 @@
     class InitialState extends State {
         @Override
         public void enter() {
-            mTetherController.sendTetherStateChangedBroadcast();
+            mTetherController.notifyInterfaceStateChange(
+                    mIfaceName, TetherInterfaceStateMachine.this,
+                    IControlsTethering.STATE_AVAILABLE, mLastError);
         }
 
         @Override
@@ -202,8 +169,7 @@
             boolean retValue = true;
             switch (message.what) {
                 case CMD_TETHER_REQUESTED:
-                    setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
-                    mTetherController.notifyInterfaceTetheringReadiness(true, TetherInterfaceStateMachine.this);
+                    mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
                     transitionTo(mTetheredState);
                     break;
                 case CMD_INTERFACE_DOWN:
@@ -221,7 +187,7 @@
         @Override
         public void enter() {
             if (!configureIfaceIp(true)) {
-                setLastError(ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR);
+                mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
                 transitionTo(mInitialState);
                 return;
             }
@@ -230,19 +196,18 @@
                 mNMService.tetherInterface(mIfaceName);
             } catch (Exception e) {
                 Log.e(TAG, "Error Tethering: " + e.toString());
-                setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);
+                mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
                 transitionTo(mInitialState);
                 return;
             }
             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
-            mTetherController.sendTetherStateChangedBroadcast();
+            mTetherController.notifyInterfaceStateChange(
+                    mIfaceName, TetherInterfaceStateMachine.this,
+                    IControlsTethering.STATE_TETHERED, mLastError);
         }
 
         @Override
         public void exit() {
-            mTetherController.notifyInterfaceTetheringReadiness(false,
-                    TetherInterfaceStateMachine.this);
-
             // Note that at this point, we're leaving the tethered state.  We can fail any
             // of these operations, but it doesn't really change that we have to try them
             // all in sequence.
@@ -251,7 +216,7 @@
             try {
                 mNMService.untetherInterface(mIfaceName);
             } catch (Exception ee) {
-                setLastError(ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR);
+                mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
                 Log.e(TAG, "Failed to untether interface: " + ee.toString());
             }
 
@@ -315,7 +280,7 @@
                                     newUpstreamIfaceName);
                         } catch (Exception e) {
                             Log.e(TAG, "Exception enabling Nat: " + e.toString());
-                            setLastError(ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR);
+                            mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
                             transitionTo(mInitialState);
                             return true;
                         }
@@ -327,8 +292,8 @@
                 case CMD_START_TETHERING_ERROR:
                 case CMD_STOP_TETHERING_ERROR:
                 case CMD_SET_DNS_FORWARDERS_ERROR:
-                    setLastErrorAndTransitionToInitialState(
-                            ConnectivityManager.TETHER_ERROR_MASTER_ERROR);
+                    mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+                    transitionTo(mInitialState);
                     break;
                 default:
                     retValue = false;
@@ -348,13 +313,10 @@
     class UnavailableState extends State {
         @Override
         public void enter() {
-            setLastError(ConnectivityManager.TETHER_ERROR_NO_ERROR);
-            mTetherController.sendTetherStateChangedBroadcast();
+            mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+            mTetherController.notifyInterfaceStateChange(
+                    mIfaceName, TetherInterfaceStateMachine.this,
+                    IControlsTethering.STATE_UNAVAILABLE, mLastError);
         }
     }
-
-    void setLastErrorAndTransitionToInitialState(int error) {
-        setLastError(error);
-        transitionTo(mInitialState);
-    }
 }
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 1b2ccd7..9220aa3 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -22,6 +22,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
+import android.app.job.JobInfo;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentProvider;
@@ -512,6 +513,16 @@
         syncAsUser(request, UserHandle.getCallingUserId());
     }
 
+    private long clampPeriod(long period) {
+        long minPeriod = JobInfo.getMinPeriodMillis() / 1000;
+        if (period < minPeriod) {
+            Slog.w(TAG, "Requested poll frequency of " + period
+                    + " seconds being rounded up to " + minPeriod + "s.");
+            period = minPeriod;
+        }
+        return period;
+    }
+
     /**
      * If the user id supplied is different to the calling user, the caller must hold the
      * INTERACT_ACROSS_USERS_FULL permission.
@@ -539,11 +550,8 @@
                 SyncStorageEngine.EndPoint info;
                 info = new SyncStorageEngine.EndPoint(
                         request.getAccount(), request.getProvider(), userId);
-                if (runAtTime < 3600) {
-                    Slog.w(TAG, "Requested poll frequency of " + runAtTime
-                            + " seconds being rounded up to 1 hour.");
-                    runAtTime = 3600;
-                }
+
+                runAtTime = clampPeriod(runAtTime);
                 // Schedule periodic sync.
                 getSyncManager().updateOrAddPeriodicSync(info, runAtTime,
                         flextime, extras);
@@ -761,11 +769,8 @@
                 "no permission to write the sync settings");
 
         int userId = UserHandle.getCallingUserId();
-        if (pollFrequency < 3600) {
-            Slog.w(TAG, "Requested poll frequency of " + pollFrequency
-                    + " seconds being rounded up to 1 hour.");
-            pollFrequency = 3600;
-        }
+
+        pollFrequency = clampPeriod(pollFrequency);
         long defaultFlex = SyncStorageEngine.calculateDefaultFlexTime(pollFrequency);
 
         long identityToken = clearCallingIdentity();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 649a27c..df91f4a 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -54,6 +54,7 @@
 
     // TODO: Evaluate the need for WeakReferences here.
     private List<PackageParser.Package> mDexoptPackages;
+    private int completeSize;
 
     public OtaDexoptService(Context context, PackageManagerService packageManagerService) {
         this.mContext = context;
@@ -91,6 +92,7 @@
             mDexoptPackages = PackageManagerServiceUtils.getPackagesForDexopt(
                     mPackageManagerService.mPackages.values(), mPackageManagerService);
         }
+        completeSize = mDexoptPackages.size();
     }
 
     @Override
@@ -111,6 +113,14 @@
     }
 
     @Override
+    public synchronized float getProgress() throws RemoteException {
+        if (completeSize == 0) {
+            return 1f;
+        }
+        return (completeSize - mDexoptPackages.size()) / ((float)completeSize);
+    }
+
+    @Override
     public synchronized void dexoptNextPackage() throws RemoteException {
         if (mDexoptPackages == null) {
             throw new IllegalStateException("dexoptNextPackage() called before prepare()");
diff --git a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
index ea9cf17..e8fdfa5 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptShellCommand.java
@@ -46,6 +46,8 @@
                     return runOtaDone();
                 case "step":
                     return runOtaStep();
+                case "progress":
+                    return runOtaProgress();
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -81,6 +83,13 @@
         return 0;
     }
 
+    private int runOtaProgress() throws RemoteException {
+        final float progress = mInterface.getProgress();
+        final PrintWriter pw = getOutPrintWriter();
+        pw.format("%.2f", progress);
+        return 0;
+    }
+
     @Override
     public void onHelp() {
         final PrintWriter pw = getOutPrintWriter();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 87141b4..0bd9822 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,11 +102,11 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.ResourcesManager;
-import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IDevicePolicyManager;
 import android.app.admin.SecurityLog;
 import android.app.backup.IBackupManager;
@@ -362,13 +362,13 @@
     static final boolean DEBUG_DEXOPT = false;
 
     private static final boolean DEBUG_ABI_SELECTION = false;
-    private static final boolean DEBUG_EPHEMERAL = false;
+    private static final boolean DEBUG_EPHEMERAL = Build.IS_DEBUGGABLE;
     private static final boolean DEBUG_TRIAGED_MISSING = false;
     private static final boolean DEBUG_APP_DATA = false;
 
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
-    private static final boolean DISABLE_EPHEMERAL_APPS = true;
+    private static final boolean DISABLE_EPHEMERAL_APPS = !Build.IS_DEBUGGABLE;
 
     private static final int RADIO_UID = Process.PHONE_UID;
     private static final int LOG_UID = Process.LOG_UID;
@@ -622,6 +622,8 @@
     @GuardedBy("mPackages")
     final ArraySet<String> mFrozenPackages = new ArraySet<>();
 
+    final ProtectedPackages mProtectedPackages = new ProtectedPackages();
+
     boolean mRestoredSettings;
 
     // System configuration read by SystemConfig.
@@ -2936,17 +2938,20 @@
     private @Nullable ComponentName getEphemeralResolverLPr() {
         final String[] packageArray =
                 mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
-        if (packageArray.length == 0) {
+        if (packageArray.length == 0 && !Build.IS_DEBUGGABLE) {
             if (DEBUG_EPHEMERAL) {
                 Slog.d(TAG, "Ephemeral resolver NOT found; empty package list");
             }
             return null;
         }
 
+        final int resolveFlags =
+                MATCH_DIRECT_BOOT_AWARE
+                | MATCH_DIRECT_BOOT_UNAWARE
+                | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
         final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE);
         final List<ResolveInfo> resolvers = queryIntentServicesInternal(resolverIntent, null,
-                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.USER_SYSTEM);
+                resolveFlags, UserHandle.USER_SYSTEM);
 
         final int N = resolvers.size();
         if (N == 0) {
@@ -2965,7 +2970,7 @@
             }
 
             final String packageName = info.serviceInfo.packageName;
-            if (!possiblePackages.contains(packageName)) {
+            if (!possiblePackages.contains(packageName) && !Build.IS_DEBUGGABLE) {
                 if (DEBUG_EPHEMERAL) {
                     Slog.d(TAG, "Ephemeral resolver not in allowed package list;"
                             + " pkg: " + packageName + ", info:" + info);
@@ -2990,9 +2995,12 @@
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE);
 
+        final int resolveFlags =
+                MATCH_DIRECT_BOOT_AWARE
+                | MATCH_DIRECT_BOOT_UNAWARE
+                | (!Build.IS_DEBUGGABLE ? MATCH_SYSTEM_ONLY : 0);
         final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, PACKAGE_MIME_TYPE,
-                MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
-                UserHandle.USER_SYSTEM);
+                resolveFlags, UserHandle.USER_SYSTEM);
         if (matches.size() == 0) {
             return null;
         } else if (matches.size() == 1) {
@@ -4994,10 +5002,10 @@
         final byte[] hostBytes = intent.getData().getHost().getBytes();
         final byte[] digestBytes = digest.digest(hostBytes);
         int shaPrefix =
-                digestBytes[0] << 24
-                | digestBytes[1] << 16
-                | digestBytes[2] << 8
-                | digestBytes[3] << 0;
+                (digestBytes[0] & 0xFF) << 24
+                | (digestBytes[1] & 0xFF) << 16
+                | (digestBytes[2] & 0xFF) << 8
+                | (digestBytes[3] & 0xFF) << 0;
         final List<EphemeralResolveInfo> ephemeralResolveInfoList =
                 mEphemeralResolverConnection.getEphemeralResolveInfoList(shaPrefix);
         if (ephemeralResolveInfoList == null || ephemeralResolveInfoList.size() == 0) {
@@ -16338,8 +16346,9 @@
                 for (int curUser : users) {
                     long timeout = SystemClock.uptimeMillis() + 5000;
                     synchronized (conn) {
-                        long now = SystemClock.uptimeMillis();
-                        while (conn.mContainerService == null && now < timeout) {
+                        long now;
+                        while (conn.mContainerService == null &&
+                                (now = SystemClock.uptimeMillis()) < timeout) {
                             try {
                                 conn.wait(timeout - now);
                             } catch (InterruptedException e) {
@@ -16393,9 +16402,7 @@
         enforceCrossUserPermission(Binder.getCallingUid(), userId,
                 true /* requireFullPermission */, false /* checkShell */, "clear application data");
 
-        final DevicePolicyManagerInternal dpmi = LocalServices
-                .getService(DevicePolicyManagerInternal.class);
-        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+        if (mProtectedPackages.canPackageBeWiped(userId, packageName)) {
             throw new SecurityException("Cannot clear data for a device owner or a profile owner");
         }
         // Queue up an async operation since the package deletion may take a little while.
@@ -17722,10 +17729,8 @@
                         + Binder.getCallingPid()
                         + ", uid=" + uid + ", package uid=" + pkgSetting.appId);
             }
-            // Don't allow changing profile and device owners. Calling into DPMS, so no locking.
-            final DevicePolicyManagerInternal dpmi = LocalServices
-                    .getService(DevicePolicyManagerInternal.class);
-            if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            // Don't allow changing profile and device owners.
+            if (mProtectedPackages.canPackageStateBeChanged(userId, packageName)) {
                 throw new SecurityException("Cannot disable a device owner or a profile owner");
             }
         }
@@ -20822,6 +20827,20 @@
                 int userId) {
             return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId);
         }
+
+        @Override
+        public void setDeviceAndProfileOwnerPackages(
+                int deviceOwnerUserId, String deviceOwnerPackage,
+                SparseArray<String> profileOwnerPackages) {
+            mProtectedPackages.setDeviceAndProfileOwnerPackages(
+                    deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+        }
+
+        @Override
+        public boolean canPackageBeWiped(int userId, String packageName) {
+            return mProtectedPackages.canPackageBeWiped(userId,
+                    packageName);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/ProtectedPackages.java b/services/core/java/com/android/server/pm/ProtectedPackages.java
new file mode 100644
index 0000000..7bdea18
--- /dev/null
+++ b/services/core/java/com/android/server/pm/ProtectedPackages.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pm;
+
+import android.annotation.UserIdInt;
+import android.os.UserHandle;
+import android.util.SparseArray;
+
+/**
+ * Manages package names that need special protection.
+ *
+ * TODO: This class should persist the information by itself, and also keeps track of device admin
+ * packages for all users.  Then PMS.isPackageDeviceAdmin() should use it instead of talking
+ * to DPMS.
+ */
+public class ProtectedPackages {
+    @UserIdInt
+    private int mDeviceOwnerUserId;
+
+    private String mDeviceOwnerPackage;
+
+    private SparseArray<String> mProfileOwnerPackages;
+
+    private final Object mLock = new Object();
+
+    /**
+     * Sets the device/profile owner information.
+     */
+    public void setDeviceAndProfileOwnerPackages(
+            int deviceOwnerUserId, String deviceOwnerPackage,
+            SparseArray<String> profileOwnerPackages) {
+        synchronized (mLock) {
+            mDeviceOwnerUserId = deviceOwnerUserId;
+            mDeviceOwnerPackage =
+                    (deviceOwnerUserId == UserHandle.USER_NULL) ? null : deviceOwnerPackage;
+            mProfileOwnerPackages = (profileOwnerPackages == null) ? null
+                    : profileOwnerPackages.clone();
+        }
+    }
+
+    private boolean hasDeviceOwnerOrProfileOwner(int userId, String packageName) {
+        if (packageName == null) {
+            return false;
+        }
+        synchronized (mLock) {
+            if (mDeviceOwnerPackage != null) {
+                if ((mDeviceOwnerUserId == userId)
+                        && (packageName.equals(mDeviceOwnerPackage))) {
+                    return true;
+                }
+            }
+            if (mProfileOwnerPackages != null) {
+                if (packageName.equals(mProfileOwnerPackages.get(userId))) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Whether a package or the components in a package's enabled state can be changed
+     * by other callers than itself.
+     */
+    public boolean canPackageStateBeChanged(@UserIdInt int userId, String packageName) {
+        return hasDeviceOwnerOrProfileOwner(userId, packageName);
+    }
+
+    /**
+     * Whether a package's data be cleared.
+     */
+    public boolean canPackageBeWiped(@UserIdInt int userId, String packageName) {
+        return hasDeviceOwnerOrProfileOwner(userId, packageName);
+    }
+}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index f336ff3..934545a 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -908,7 +908,7 @@
                 if (operation != ShortcutService.OPERATION_UPDATE) {
                     // This method may be called before validating shortcuts, so this may happen,
                     // and is a caller side error.
-                    throw new NullPointerException("activity must be provided");
+                    throw new NullPointerException("Activity must be provided");
                 }
                 continue; // Activity can be null for update.
             }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 95689ca..2f44640 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -31,6 +31,7 @@
 import android.app.IActivityManager;
 import android.app.IStopUserCallback;
 import android.app.KeyguardManager;
+import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -170,6 +171,12 @@
     private static final String RESTRICTIONS_FILE_PREFIX = "res_";
     private static final String XML_SUFFIX = ".xml";
 
+    private static final int ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION =
+            UserInfo.FLAG_MANAGED_PROFILE
+            | UserInfo.FLAG_EPHEMERAL
+            | UserInfo.FLAG_RESTRICTED
+            | UserInfo.FLAG_GUEST;
+
     private static final int MIN_USER_ID = 10;
     // We need to keep process uid within Integer.MAX_VALUE.
     private static final int MAX_USER_ID = Integer.MAX_VALUE / UserHandle.PER_USER_RANGE;
@@ -325,6 +332,27 @@
 
     private final LockPatternUtils mLockPatternUtils;
 
+    private final String ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK =
+            "com.android.server.pm.DISABLE_QUIET_MODE_AFTER_UNLOCK";
+
+    private final BroadcastReceiver mDisableQuietModeCallback = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
+                final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
+                setQuietModeEnabled(userHandle, false);
+                if (target != null) {
+                    try {
+                        mContext.startIntentSender(target, null, 0, 0, 0);
+                    } catch (IntentSender.SendIntentException e) {
+                        /* ignore */
+                    }
+                }
+            }
+        }
+    };
+
     /**
      * Whether all users should be created ephemeral.
      */
@@ -419,7 +447,10 @@
         }
 
         maybeInitializeDemoMode(UserHandle.USER_SYSTEM);
-}
+        mContext.registerReceiver(mDisableQuietModeCallback,
+                new IntentFilter(ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK),
+                null, mHandler);
+    }
 
     @Override
     public String getUserAccount(int userId) {
@@ -470,7 +501,7 @@
 
     @Override
     public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
-        checkManageUsersPermission("query users");
+        checkManageOrCreateUsersPermission("query users");
         synchronized (mUsersLock) {
             ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size());
             final int userSize = mUsers.size();
@@ -708,6 +739,7 @@
 
     @Override
     public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) {
+        checkManageUsersPermission("silence profile");
         if (StorageManager.isUserKeyUnlocked(userHandle)
                 || !mLockPatternUtils.isSecure(userHandle)) {
             // if the user is already unlocked, no need to show a profile challenge
@@ -728,9 +760,24 @@
             if (unlockIntent == null) {
                 return false;
             }
+            final Intent callBackIntent = new Intent(
+                    ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK);
             if (target != null) {
-                unlockIntent.putExtra(Intent.EXTRA_INTENT, target);
+                callBackIntent.putExtra(Intent.EXTRA_INTENT, target);
             }
+            callBackIntent.putExtra(Intent.EXTRA_USER_ID, userHandle);
+            callBackIntent.setPackage(mContext.getPackageName());
+            callBackIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+            final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+                    mContext,
+                    0,
+                    callBackIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT |
+                            PendingIntent.FLAG_ONE_SHOT |
+                            PendingIntent.FLAG_IMMUTABLE);
+            // After unlocking the challenge, it will disable quiet mode and run the original
+            // intentSender
+            unlockIntent.putExtra(Intent.EXTRA_INTENT, pendingIntent.getIntentSender());
             unlockIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
             mContext.startActivity(unlockIntent);
         } finally {
@@ -1412,6 +1459,41 @@
     }
 
     /**
+     * Enforces that only the system UID or root's UID or apps that have the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}
+     * can make certain calls to the UserManager.
+     *
+     * @param message used as message if SecurityException is thrown
+     * @throws SecurityException if the caller is not system or root
+     * @see #hasManageOrCreateUsersPermission()
+     */
+    private static final void checkManageOrCreateUsersPermission(String message) {
+        if (!hasManageOrCreateUsersPermission()) {
+            throw new SecurityException(
+                    "You either need MANAGE_USERS or CREATE_USERS permission to: " + message);
+        }
+    }
+
+    /**
+     * Similar to {@link #checkManageOrCreateUsersPermission(String)} but when the caller is tries
+     * to create user/profiles other than what is allowed for
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS} permission, then it will only
+     * allow callers with {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} permission.
+     */
+    private static final void checkManageOrCreateUsersPermission(int creationFlags) {
+        if ((creationFlags & ~ALLOWED_FLAGS_FOR_CREATE_USERS_PERMISSION) == 0) {
+            if (!hasManageOrCreateUsersPermission()) {
+                throw new SecurityException("You either need MANAGE_USERS or CREATE_USERS "
+                        + "permission to create an user with flags: " + creationFlags);
+            }
+        } else if (!hasManageUsersPermission()) {
+            throw new SecurityException("You need MANAGE_USERS permission to create an user "
+                    + " with flags: " + creationFlags);
+        }
+    }
+
+    /**
      * @return whether the calling UID is system UID or root's UID or the calling app has the
      * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS}.
      */
@@ -1425,6 +1507,23 @@
     }
 
     /**
+     * @return whether the calling UID is system UID or root's UID or the calling app has the
+     * {@link android.Manifest.permission#MANAGE_USERS MANAGE_USERS} or
+     * {@link android.Manifest.permission#CREATE_USERS CREATE_USERS}.
+     */
+    private static final boolean hasManageOrCreateUsersPermission() {
+        final int callingUid = Binder.getCallingUid();
+        return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
+                || callingUid == Process.ROOT_UID
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.MANAGE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
+                || ActivityManager.checkComponentPermission(
+                        android.Manifest.permission.CREATE_USERS,
+                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+    }
+
+    /**
      * Enforces that only the system UID or root's UID (on any user) can make certain calls to the
      * UserManager.
      *
@@ -2010,13 +2109,13 @@
 
     @Override
     public UserInfo createProfileForUser(String name, int flags, int userId) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         return createUserInternal(name, flags, userId);
     }
 
     @Override
     public UserInfo createUser(String name, int flags) {
-        checkManageUsersPermission("Only the system can create users");
+        checkManageOrCreateUsersPermission(flags);
         return createUserInternal(name, flags, UserHandle.USER_NULL);
     }
 
@@ -2262,7 +2361,7 @@
      */
     @Override
     public boolean removeUser(int userHandle) {
-        checkManageUsersPermission("Only the system can remove users");
+        checkManageOrCreateUsersPermission("Only the system can remove users");
         if (getUserRestrictions(UserHandle.getCallingUserId()).getBoolean(
                 UserManager.DISALLOW_REMOVE_USER, false)) {
             Log.w(LOG_TAG, "Cannot remove user. DISALLOW_REMOVE_USER is enabled.");
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 2cc4984..827d51c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2598,8 +2598,13 @@
             final PhoneWindow win = new PhoneWindow(context);
             win.setIsStartingWindow(true);
 
-            final Resources r = context.getResources();
-            win.setTitle(r.getText(labelRes, nonLocalizedLabel));
+            CharSequence label = context.getResources().getText(labelRes, null);
+            // Only change the accessibility title if the label is localized
+            if (label != null) {
+                win.setTitle(label, true);
+            } else {
+                win.setTitle(nonLocalizedLabel, false);
+            }
 
             win.setType(
                 WindowManager.LayoutParams.TYPE_APPLICATION_STARTING);
@@ -6873,9 +6878,7 @@
             @Override public void run() {
                 if (mBootMsgDialog == null) {
                     int theme;
-                    if (mHasFeatureWatch) {
-                        theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
-                    } else if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
+                    if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
                         theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
                     } else {
                         theme = 0;
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 3700c71..b4c4bd8 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -46,11 +46,12 @@
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
 import android.service.vr.VrListenerService;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.SparseArray;
-
 import com.android.internal.R;
+import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.android.server.SystemService;
 import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -67,6 +68,7 @@
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 
 /**
@@ -197,29 +199,44 @@
 
     private final class NotificationAccessManager {
         private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>();
+        private final ArrayMap<String, Integer> mNotificationAccessPackageToUserId =
+                new ArrayMap<>();
 
         public void update(Collection<String> packageNames) {
             int currentUserId = ActivityManager.getCurrentUser();
 
-            UserHandle currentUserHandle = new UserHandle(currentUserId);
-
             ArraySet<String> allowed = mAllowedPackages.get(currentUserId);
             if (allowed == null) {
                 allowed = new ArraySet<>();
             }
 
+            // Make sure we revoke notification access for listeners in other users
+            final int listenerCount = mNotificationAccessPackageToUserId.size();
+            for (int i = listenerCount - 1; i >= 0; i--) {
+                final int grantUserId = mNotificationAccessPackageToUserId.valueAt(i);
+                if (grantUserId != currentUserId) {
+                    String packageName = mNotificationAccessPackageToUserId.keyAt(i);
+                    revokeNotificationListenerAccess(packageName, grantUserId);
+                    revokeNotificationPolicyAccess(packageName);
+                    revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
+                    mNotificationAccessPackageToUserId.removeAt(i);
+                }
+            }
+
             for (String pkg : allowed) {
                 if (!packageNames.contains(pkg)) {
-                    revokeNotificationListenerAccess(pkg);
+                    revokeNotificationListenerAccess(pkg, currentUserId);
                     revokeNotificationPolicyAccess(pkg);
-                    revokeCoarseLocationAccess(pkg, currentUserHandle);
+                    revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
+                    mNotificationAccessPackageToUserId.remove(pkg);
                 }
             }
             for (String pkg : packageNames) {
                 if (!allowed.contains(pkg)) {
                     grantNotificationPolicyAccess(pkg);
-                    grantNotificationListenerAccess(pkg, currentUserHandle);
-                    grantCoarseLocationAccess(pkg, currentUserHandle);
+                    grantNotificationListenerAccess(pkg, currentUserId);
+                    grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
+                    mNotificationAccessPackageToUserId.put(pkg, currentUserId);
                 }
             }
 
@@ -229,7 +246,6 @@
         }
     }
 
-
     /**
      * Called when a user, package, or setting changes that could affect whether or not the
      * currently bound VrListenerService is changed.
@@ -535,17 +551,33 @@
         }
     }
 
-    private void updateOverlayStateLocked(ComponentName exemptedComponent) {
+    private void updateOverlayStateLocked(String exemptedPackage, int newUserId, int oldUserId) {
+        AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+
+        // If user changed drop restrictions for the old user.
+        if (oldUserId != newUserId) {
+            appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                    false, mOverlayToken, null, oldUserId);
+        }
+
+        // Apply the restrictions for the current user based on vr state
+        String[] exemptions = (exemptedPackage == null) ? new String[0] :
+                new String[] { exemptedPackage };
+
+        appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                mVrModeEnabled, mOverlayToken, exemptions, newUserId);
+    }
+
+    private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
+            String oldVrServicePackage, int oldUserId) {
+        // If VR state changed and we also have a VR service change.
+        if (Objects.equals(newVrServicePackage, oldVrServicePackage)) {
+            return;
+        }
         final long identity = Binder.clearCallingIdentity();
         try {
-            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-            if (appOpsManager != null) {
-                String[] exemptions = (exemptedComponent == null) ? new String[0] :
-                        new String[] { exemptedComponent.getPackageName() };
-
-                appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
-                        mVrModeEnabled, mOverlayToken, exemptions);
-            }
+            // Set overlay exception state based on VR enabled and current service
+            updateOverlayStateLocked(newVrServicePackage, newUserId, oldUserId);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -578,8 +610,12 @@
                 return validUserComponent; // Disabled -> Disabled transition does nothing.
             }
 
+            String oldVrServicePackage = mCurrentVrService != null
+                    ? mCurrentVrService.getComponent().getPackageName() : null;
+            final int oldUserId = mCurrentVrModeUser;
+
             // Always send mode change events.
-            changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
+            changeVrModeLocked(enabled);
 
             if (!enabled || !validUserComponent) {
                 // Unbind whatever is running
@@ -606,12 +642,25 @@
                 }
             }
 
-            if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent))  {
+            if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
                 mCurrentVrModeComponent = calling;
+                sendUpdatedCaller = true;
+            }
+
+            if (mCurrentVrModeUser != userId) {
                 mCurrentVrModeUser = userId;
                 sendUpdatedCaller = true;
             }
 
+            String newVrServicePackage = mCurrentVrService != null
+                    ? mCurrentVrService.getComponent().getPackageName() : null;
+            final int newUserId = mCurrentVrModeUser;
+
+            // Update AppOps settings that change state when entering/exiting VR mode, or changing
+            // the current VrListenerService.
+            updateDependentAppOpsLocked(newVrServicePackage, newUserId,
+                    oldVrServicePackage, oldUserId);
+
             if (mCurrentVrService != null && sendUpdatedCaller) {
                 final ComponentName c = mCurrentVrModeComponent;
                 mCurrentVrService.sendEvent(new PendingEvent() {
@@ -645,18 +694,6 @@
         return true;
     }
 
-    private void grantCoarseLocationAccess(String pkg, UserHandle userId) {
-        PackageManager pm = mContext.getPackageManager();
-        pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION,
-                userId);
-    }
-
-    private void revokeCoarseLocationAccess(String pkg, UserHandle userId) {
-        PackageManager pm = mContext.getPackageManager();
-        pm.revokeRuntimePermission(pkg,
-                android.Manifest.permission.ACCESS_COARSE_LOCATION, userId);
-    }
-
     private void grantNotificationPolicyAccess(String pkg) {
         NotificationManager nm = mContext.getSystemService(NotificationManager.class);
         nm.setNotificationPolicyAccessGranted(pkg, true);
@@ -670,14 +707,14 @@
         nm.setNotificationPolicyAccessGranted(pkg, false);
     }
 
-    private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
+    private void grantNotificationListenerAccess(String pkg, int userId) {
         PackageManager pm = mContext.getPackageManager();
         ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
-                userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
+                userId, NotificationListenerService.SERVICE_INTERFACE,
                 android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
         ContentResolver resolver = mContext.getContentResolver();
 
-        ArraySet<String> current = getCurrentNotifListeners(resolver);
+        ArraySet<String> current = getNotificationListeners(resolver, userId);
 
         for (ComponentName c : possibleServices) {
             String flatName = c.flattenToString();
@@ -689,14 +726,16 @@
 
         if (current.size() > 0) {
             String flatSettings = formatSettings(current);
-            Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                    flatSettings);
+            Settings.Secure.putStringForUser(resolver,
+                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                    flatSettings, userId);
         }
     }
 
-    private void revokeNotificationListenerAccess(String pkg) {
+    private void revokeNotificationListenerAccess(String pkg, int userId) {
         ContentResolver resolver = mContext.getContentResolver();
-        ArraySet<String> current = getCurrentNotifListeners(resolver);
+
+        ArraySet<String> current = getNotificationListeners(resolver, userId);
 
         ArrayList<String> toRemove = new ArrayList<>();
 
@@ -710,14 +749,37 @@
         current.removeAll(toRemove);
 
         String flatSettings = formatSettings(current);
-        Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
-                flatSettings);
-
+        Settings.Secure.putStringForUser(resolver,
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
+                flatSettings, userId);
     }
 
-    private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
-        String flat = Settings.Secure.getString(resolver,
-                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
+    private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
+        // Don't clobber the user if permission set in current state explicitly
+        if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
+            mContext.getPackageManager().grantRuntimePermission(pkg,
+                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+        }
+    }
+
+    private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
+        // Don't clobber the user if permission set in current state explicitly
+        if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
+            mContext.getPackageManager().revokeRuntimePermission(pkg,
+                    Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
+        }
+    }
+
+    private boolean isPermissionUserUpdated(String permission, String pkg, int userId) {
+        final int flags = mContext.getPackageManager().getPermissionFlags(
+                permission, pkg, new UserHandle(userId));
+        return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+                | PackageManager.FLAG_PERMISSION_USER_FIXED)) != 0;
+    }
+
+    private ArraySet<String> getNotificationListeners(ContentResolver resolver, int userId) {
+        String flat = Settings.Secure.getStringForUser(resolver,
+                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, userId);
 
         ArraySet<String> current = new ArraySet<>();
         if (flat != null) {
@@ -763,9 +825,8 @@
      * Note: Must be called while holding {@code mLock}.
      *
      * @param enabled new state of the VR mode.
-     * @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
      */
-    private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) {
+    private void changeVrModeLocked(boolean enabled) {
         if (mVrModeEnabled != enabled) {
             mVrModeEnabled = enabled;
 
@@ -773,7 +834,6 @@
             Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
             setVrModeNative(mVrModeEnabled);
 
-            updateOverlayStateLocked(exemptedComponent);
             onVrModeChangedLocked();
         }
     }
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 101f56f..8be5dfb 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -1203,9 +1203,6 @@
             window.layer = windowState.mLayer;
             window.token = windowState.mClient.asBinder();
             window.title = windowState.mAttrs.accessibilityTitle;
-            if (window.title == null) {
-                window.title = windowState.mAttrs.getTitle();
-            }
             window.accessibilityIdOfAnchor = windowState.mAttrs.accessibilityIdOfAnchor;
 
             WindowState attachedWindow = windowState.mAttachedWindow;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 881fc10..36d9697 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -824,22 +824,11 @@
             mTmpSize.bottom = mTmpSize.top + 1;
         }
 
-        final int displayId = w.getDisplayId();
-        float scale = 1.0f;
-        // Magnification is supported only for the default display.
-        if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
-            final MagnificationSpec spec =
-                    mService.mAccessibilityController.getMagnificationSpecForWindowLocked(w);
-            if (spec != null && !spec.isNop()) {
-                scale = spec.scale;
-            }
-        }
-
         // Adjust for surface insets.
-        mTmpSize.left -= scale * attrs.surfaceInsets.left;
-        mTmpSize.top -= scale * attrs.surfaceInsets.top;
-        mTmpSize.right += scale * attrs.surfaceInsets.right;
-        mTmpSize.bottom += scale * attrs.surfaceInsets.bottom;
+        mTmpSize.left -= attrs.surfaceInsets.left;
+        mTmpSize.top -= attrs.surfaceInsets.top;
+        mTmpSize.right += attrs.surfaceInsets.right;
+        mTmpSize.bottom += attrs.surfaceInsets.bottom;
     }
 
     boolean hasSurface() {
@@ -1300,9 +1289,13 @@
     void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
                 + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
-        if (!clipRect.equals(mLastClipRect)) {
-            mLastClipRect.set(clipRect);
-            mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+        if (clipRect != null) {
+            if (!clipRect.equals(mLastClipRect)) {
+                mLastClipRect.set(clipRect);
+                mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
+            }
+        } else {
+            mSurfaceController.clearCropInTransaction(recoveringMemory);
         }
         if (!finalClipRect.equals(mLastFinalClipRect)) {
             mLastFinalClipRect.set(finalClipRect);
@@ -1491,14 +1484,16 @@
             mSurfaceController.setPositionAppliesWithResizeInTransaction(true);
             mSurfaceController.forceScaleableInTransaction(false);
         }
+
+        Rect clipRect = mTmpClipRect;
         if (w.inPinnedWorkspace()) {
-            mTmpClipRect.set(0, 0, -1, -1);
+            clipRect = null;
             task.mStack.getDimBounds(mTmpFinalClipRect);
             mTmpFinalClipRect.inset(-w.mAttrs.surfaceInsets.left, -w.mAttrs.surfaceInsets.top,
                     -w.mAttrs.surfaceInsets.right, -w.mAttrs.surfaceInsets.bottom);
         }
 
-        updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
+        updateSurfaceWindowCrop(clipRect, mTmpFinalClipRect, recoveringMemory);
 
         mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * mExtraHScale,
                 mDtDx * w.mVScale * mExtraVScale,
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index c30da14..fd0bb99 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -26,6 +26,7 @@
 import static android.view.Surface.SCALING_MODE_FREEZE;
 import static android.view.Surface.SCALING_MODE_SCALE_TO_WINDOW;
 
+import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.Rect;
@@ -78,7 +79,15 @@
 
         title = name;
 
-        if (DEBUG_SURFACE_TRACE) {
+        // For opaque child windows placed under parent windows,
+        // we use a special SurfaceControl which mirrors commands
+        // to a black-out layer placed one Z-layer below the surface.
+        // This prevents holes to whatever app/wallpaper is underneath.
+        if (animator.mWin.isChildWindow() &&
+                animator.mWin.mSubLayer < 0) {
+            mSurfaceControl = new SurfaceControlWithBackground(s,
+                    name, w, h, format, flags);
+        } else if (DEBUG_SURFACE_TRACE) {
             mSurfaceControl = new SurfaceTrace(
                     s, name, w, h, format, flags);
         } else {
@@ -176,7 +185,7 @@
         if (SHOW_TRANSACTIONS) logSurface(
                 "CROP " + clipRect.toShortString(), null);
         try {
-            if (clipRect.width() != 0 && clipRect.height() != 0) {
+            if (clipRect.width() > 0 && clipRect.height() > 0) {
                 mSurfaceControl.setWindowCrop(clipRect);
                 mHiddenForCrop = false;
                 updateVisibility();
@@ -194,6 +203,20 @@
         }
     }
 
+    void clearCropInTransaction(boolean recoveringMemory) {
+        if (SHOW_TRANSACTIONS) logSurface(
+                "CLEAR CROP", null);
+        try {
+            Rect clipRect = new Rect(0, 0, -1, -1);
+            mSurfaceControl.setWindowCrop(clipRect);
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error setting clearing crop of " + this, e);
+            if (!recoveringMemory) {
+                mAnimator.reclaimSomeSurfaceMemory("crop", true);
+            }
+        }
+    }
+
     void setFinalCropInTransaction(Rect clipRect) {
         if (SHOW_TRANSACTIONS) logSurface(
                 "FINAL CROP " + clipRect.toShortString(), null);
@@ -730,4 +753,125 @@
                     + " (" + mDsdx + "," + mDtdx + "," + mDsdy + "," + mDtdy + ")";
         }
     }
+
+    private static class SurfaceControlWithBackground extends SurfaceControl {
+        private SurfaceControl mBackgroundControl;
+        private boolean mOpaque = true;
+        private boolean mVisible = false;
+
+        public SurfaceControlWithBackground(SurfaceSession s,
+                       String name, int w, int h, int format, int flags)
+                   throws OutOfResourcesException {
+            super(s, name, w, h, format, flags);
+            mBackgroundControl = new SurfaceControl(s, name, w, h,
+                    PixelFormat.OPAQUE, flags | SurfaceControl.FX_SURFACE_DIM);
+            mOpaque = (flags & SurfaceControl.OPAQUE) != 0;
+        }
+
+        @Override
+        public void setAlpha(float alpha) {
+            super.setAlpha(alpha);
+            mBackgroundControl.setAlpha(alpha);
+        }
+
+        @Override
+        public void setLayer(int zorder) {
+            super.setLayer(zorder);
+            mBackgroundControl.setLayer(zorder - 1);
+        }
+
+        @Override
+        public void setPosition(float x, float y) {
+            super.setPosition(x, y);
+            mBackgroundControl.setPosition(x, y);
+        }
+
+        @Override
+        public void setSize(int w, int h) {
+            super.setSize(w, h);
+            mBackgroundControl.setSize(w, h);
+        }
+
+        @Override
+        public void setWindowCrop(Rect crop) {
+            super.setWindowCrop(crop);
+            mBackgroundControl.setWindowCrop(crop);
+        }
+
+        @Override
+        public void setFinalCrop(Rect crop) {
+            super.setFinalCrop(crop);
+            mBackgroundControl.setFinalCrop(crop);
+        }
+
+        @Override
+        public void setLayerStack(int layerStack) {
+            super.setLayerStack(layerStack);
+            mBackgroundControl.setLayerStack(layerStack);
+        }
+
+        @Override
+        public void setOpaque(boolean isOpaque) {
+            super.setOpaque(isOpaque);
+            mOpaque = isOpaque;
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void setSecure(boolean isSecure) {
+            super.setSecure(isSecure);
+        }
+
+        @Override
+        public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
+            super.setMatrix(dsdx, dtdx, dsdy, dtdy);
+            mBackgroundControl.setMatrix(dsdx, dtdx, dsdy, dtdy);
+        }
+
+        @Override
+        public void hide() {
+            mVisible = false;
+            super.hide();
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void show() {
+            mVisible = true;
+            super.show();
+            updateBackgroundVisibility();
+        }
+
+        @Override
+        public void destroy() {
+            super.destroy();
+            mBackgroundControl.destroy();
+        }
+
+        @Override
+        public void release() {
+            super.release();
+            mBackgroundControl.release();
+        }
+
+        @Override
+        public void setTransparentRegionHint(Region region) {
+            super.setTransparentRegionHint(region);
+            mBackgroundControl.setTransparentRegionHint(region);
+        }
+
+        @Override
+        public void deferTransactionUntil(IBinder handle, long frame) {
+            super.deferTransactionUntil(handle, frame);
+            mBackgroundControl.deferTransactionUntil(handle, frame);
+        }
+
+        private void updateBackgroundVisibility() {
+            if (mOpaque && mVisible) {
+                mBackgroundControl.show();
+            } else {
+                mBackgroundControl.hide();
+            }
+        }
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 9a7e64b3..b528016 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -1338,7 +1338,8 @@
         }
 
         Owners newOwners() {
-            return new Owners(mContext, getUserManager(), getUserManagerInternal());
+            return new Owners(getUserManager(), getUserManagerInternal(),
+                    getPackageManagerInternal());
         }
 
         UserManager getUserManager() {
@@ -8134,45 +8135,27 @@
         }
 
         @Override
-        public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
-            if (!mHasFeature || packageName == null) {
-                return false;
-            }
-            if (userId < 0) {
-                throw new UnsupportedOperationException("userId should be >= 0");
-            }
-            synchronized (DevicePolicyManagerService.this) {
-                if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
-                    return true;
-                }
-                if (userId == mOwners.getDeviceOwnerUserId()
-                        && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
-        @Override
         public Intent createPackageSuspendedDialogIntent(String packageName, int userId) {
             Intent intent = new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS);
             intent.putExtra(Intent.EXTRA_USER_ID, userId);
             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-            synchronized (DevicePolicyManagerService.this) {
-                ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
-                if (profileOwner != null) {
-                    intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, profileOwner);
-                    return intent;
-                }
 
-                if (mOwners.getDeviceOwnerUserId() == userId) {
-                    ComponentName deviceOwner = mOwners.getDeviceOwnerComponent();
-                    if (deviceOwner != null) {
-                        intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceOwner);
-                        return intent;
-                    }
-                }
+            // This method is called from AM with its lock held, so don't take the DPMS lock.
+            // b/29242568
+
+            ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
+            if (profileOwner != null) {
+                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, profileOwner);
+                return intent;
             }
+
+            final Pair<Integer, ComponentName> deviceOwner =
+                    mOwners.getDeviceOwnerUserIdAndComponent();
+            if (deviceOwner != null && deviceOwner.first == userId) {
+                intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, deviceOwner.second);
+                return intent;
+            }
+
             // We're not specifying the device admin because there isn't one.
             return intent;
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index b316cbd..1ae1a77 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -16,9 +16,10 @@
 
 package com.android.server.devicepolicy;
 
+import android.annotation.Nullable;
 import android.app.admin.SystemUpdatePolicy;
 import android.content.ComponentName;
-import android.content.Context;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
 import android.os.Environment;
 import android.os.UserHandle;
@@ -27,7 +28,9 @@
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
@@ -52,8 +55,8 @@
  * 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.
  *
- * <p>This class is not thread safe.  (i.e. access to this class must always be synchronized
- * in the caller side.)
+ * <p>This class is thread safe, so individual methods can safely be called without locking.
+ * However, caller must still synchronize on their side to ensure integrity between multiple calls.
  */
 class Owners {
     private static final String TAG = "DevicePolicyManagerService";
@@ -86,6 +89,7 @@
 
     private final UserManager mUserManager;
     private final UserManagerInternal mUserManagerInternal;
+    private final PackageManagerInternal mPackageManagerInternal;
 
     // Internal state for the device owner package.
     private OwnerInfo mDeviceOwner;
@@ -98,77 +102,117 @@
     // Local system update policy controllable by device owner.
     private SystemUpdatePolicy mSystemUpdatePolicy;
 
-    public Owners(Context context, UserManager userManager,
-            UserManagerInternal userManagerInternal) {
+    private final Object mLock = new Object();
+
+    public Owners(UserManager userManager,
+            UserManagerInternal userManagerInternal,
+            PackageManagerInternal packageManagerInternal) {
         mUserManager = userManager;
         mUserManagerInternal = userManagerInternal;
+        mPackageManagerInternal = packageManagerInternal;
     }
 
     /**
      * Load configuration from the disk.
      */
     void load() {
-        // First, try to read from the legacy file.
-        final File legacy = getLegacyConfigFileWithTestOverride();
+        synchronized (mLock) {
+            // First, try to read from the legacy file.
+            final File legacy = getLegacyConfigFileWithTestOverride();
 
-        final List<UserInfo> users = mUserManager.getUsers();
+            final List<UserInfo> users = mUserManager.getUsers();
 
-        if (readLegacyOwnerFile(legacy)) {
-            if (DEBUG) {
-                Log.d(TAG, "Legacy config file found.");
-            }
+            if (readLegacyOwnerFileLocked(legacy)) {
+                if (DEBUG) {
+                    Log.d(TAG, "Legacy config file found.");
+                }
 
-            // Legacy file exists, write to new files and remove the legacy one.
-            writeDeviceOwner();
-            for (int userId : getProfileOwnerKeys()) {
-                writeProfileOwner(userId);
-            }
-            if (DEBUG) {
-                Log.d(TAG, "Deleting legacy config file");
-            }
-            if (!legacy.delete()) {
-                Slog.e(TAG, "Failed to remove the legacy setting file");
-            }
-        } else {
-            // No legacy file, read from the new format files.
-            new DeviceOwnerReadWriter().readFromFileLocked();
+                // Legacy file exists, write to new files and remove the legacy one.
+                writeDeviceOwner();
+                for (int userId : getProfileOwnerKeys()) {
+                    writeProfileOwner(userId);
+                }
+                if (DEBUG) {
+                    Log.d(TAG, "Deleting legacy config file");
+                }
+                if (!legacy.delete()) {
+                    Slog.e(TAG, "Failed to remove the legacy setting file");
+                }
+            } else {
+                // No legacy file, read from the new format files.
+                new DeviceOwnerReadWriter().readFromFileLocked();
 
+                for (UserInfo ui : users) {
+                    new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
+                }
+            }
+            mUserManagerInternal.setDeviceManaged(hasDeviceOwner());
             for (UserInfo ui : users) {
-                new ProfileOwnerReadWriter(ui.id).readFromFileLocked();
+                mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id));
             }
+            if (hasDeviceOwner() && hasProfileOwner(getDeviceOwnerUserId())) {
+                Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
+                        getDeviceOwnerUserId()));
+            }
+            pushToPackageManagerLocked();
         }
-        mUserManagerInternal.setDeviceManaged(hasDeviceOwner());
-        for (UserInfo ui : users) {
-            mUserManagerInternal.setUserManaged(ui.id, hasProfileOwner(ui.id));
+    }
+
+    private void pushToPackageManagerLocked() {
+        final SparseArray<String> po = new SparseArray<>();
+        for (int i = mProfileOwners.size() - 1; i >= 0; i--) {
+            po.put(mProfileOwners.keyAt(i), mProfileOwners.valueAt(i).packageName);
         }
-        if (hasDeviceOwner() && hasProfileOwner(getDeviceOwnerUserId())) {
-            Slog.w(TAG, String.format("User %d has both DO and PO, which is not supported",
-                    getDeviceOwnerUserId()));
-        }
+        mPackageManagerInternal.setDeviceAndProfileOwnerPackages(
+                mDeviceOwnerUserId, (mDeviceOwner != null ? mDeviceOwner.packageName : null),
+                po);
     }
 
     String getDeviceOwnerPackageName() {
-        return mDeviceOwner != null ? mDeviceOwner.packageName : null;
+        synchronized (mLock) {
+            return mDeviceOwner != null ? mDeviceOwner.packageName : null;
+        }
     }
 
     int getDeviceOwnerUserId() {
-        return mDeviceOwnerUserId;
+        synchronized (mLock) {
+            return mDeviceOwnerUserId;
+        }
+    }
+
+    @Nullable
+    Pair<Integer, ComponentName> getDeviceOwnerUserIdAndComponent() {
+        synchronized (mLock) {
+            if (mDeviceOwner == null) {
+                return null;
+            } else {
+                return Pair.create(mDeviceOwnerUserId, mDeviceOwner.admin);
+            }
+        }
     }
 
     String getDeviceOwnerName() {
-        return mDeviceOwner != null ? mDeviceOwner.name : null;
+        synchronized (mLock) {
+            return mDeviceOwner != null ? mDeviceOwner.name : null;
+        }
     }
 
     ComponentName getDeviceOwnerComponent() {
-        return mDeviceOwner != null ? mDeviceOwner.admin : null;
+        synchronized (mLock) {
+            return mDeviceOwner != null ? mDeviceOwner.admin : null;
+        }
     }
 
     String getDeviceOwnerRemoteBugreportUri() {
-        return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null;
+        synchronized (mLock) {
+            return mDeviceOwner != null ? mDeviceOwner.remoteBugreportUri : null;
+        }
     }
 
     String getDeviceOwnerRemoteBugreportHash() {
-        return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null;
+        synchronized (mLock) {
+            return mDeviceOwner != null ? mDeviceOwner.remoteBugreportHash : null;
+        }
     }
 
     void setDeviceOwner(ComponentName admin, String ownerName, int userId) {
@@ -176,128 +220,172 @@
             Slog.e(TAG, "Invalid user id for device owner user: " + userId);
             return;
         }
-        // For a newly set DO, there's no need for migration.
-        setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
-                /* userRestrictionsMigrated =*/ true);
+        synchronized (mLock) {
+            // For a newly set DO, there's no need for migration.
+            setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
+                    /* userRestrictionsMigrated =*/ true);
+        }
     }
 
     // Note this should be only called during migration.  Normally when DO is set,
     // userRestrictionsMigrated should always be true.
     void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
             boolean userRestrictionsMigrated) {
-        mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
-                /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
-        mDeviceOwnerUserId = userId;
+        synchronized (mLock) {
+            mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated,
+                    /* remoteBugreportUri =*/ null, /* remoteBugreportHash =*/ null);
+            mDeviceOwnerUserId = userId;
 
-        mUserManagerInternal.setDeviceManaged(true);
+            mUserManagerInternal.setDeviceManaged(true);
+            pushToPackageManagerLocked();
+        }
     }
 
     void clearDeviceOwner() {
-        mDeviceOwner = null;
-        mDeviceOwnerUserId = UserHandle.USER_NULL;
+        synchronized (mLock) {
+            mDeviceOwner = null;
+            mDeviceOwnerUserId = UserHandle.USER_NULL;
 
-        mUserManagerInternal.setDeviceManaged(false);
+            mUserManagerInternal.setDeviceManaged(false);
+            pushToPackageManagerLocked();
+        }
     }
 
     void setProfileOwner(ComponentName admin, String ownerName, int userId) {
-        // For a newly set PO, there's no need for migration.
-        mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
-                /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
-                /* remoteBugreportHash =*/ null));
-        mUserManagerInternal.setUserManaged(userId, true);
+        synchronized (mLock) {
+            // For a newly set PO, there's no need for migration.
+            mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
+                    /* userRestrictionsMigrated =*/ true, /* remoteBugreportUri =*/ null,
+                    /* remoteBugreportHash =*/ null));
+            mUserManagerInternal.setUserManaged(userId, true);
+            pushToPackageManagerLocked();
+        }
     }
 
     void removeProfileOwner(int userId) {
-        mProfileOwners.remove(userId);
-        mUserManagerInternal.setUserManaged(userId, false);
+        synchronized (mLock) {
+            mProfileOwners.remove(userId);
+            mUserManagerInternal.setUserManaged(userId, false);
+            pushToPackageManagerLocked();
+        }
     }
 
     ComponentName getProfileOwnerComponent(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.admin : null;
+        synchronized (mLock) {
+            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;
+        synchronized (mLock) {
+            OwnerInfo profileOwner = mProfileOwners.get(userId);
+            return profileOwner != null ? profileOwner.name : null;
+        }
     }
 
     String getProfileOwnerPackage(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null ? profileOwner.packageName : null;
+        synchronized (mLock) {
+            OwnerInfo profileOwner = mProfileOwners.get(userId);
+            return profileOwner != null ? profileOwner.packageName : null;
+        }
     }
 
     Set<Integer> getProfileOwnerKeys() {
-        return mProfileOwners.keySet();
+        synchronized (mLock) {
+            return mProfileOwners.keySet();
+        }
     }
 
     SystemUpdatePolicy getSystemUpdatePolicy() {
-        return mSystemUpdatePolicy;
+        synchronized (mLock) {
+            return mSystemUpdatePolicy;
+        }
     }
 
     void setSystemUpdatePolicy(SystemUpdatePolicy systemUpdatePolicy) {
-        mSystemUpdatePolicy = systemUpdatePolicy;
+        synchronized (mLock) {
+            mSystemUpdatePolicy = systemUpdatePolicy;
+        }
     }
 
     void clearSystemUpdatePolicy() {
-        mSystemUpdatePolicy = null;
+        synchronized (mLock) {
+            mSystemUpdatePolicy = null;
+        }
     }
 
     boolean hasDeviceOwner() {
-        return mDeviceOwner != null;
+        synchronized (mLock) {
+            return mDeviceOwner != null;
+        }
     }
 
     boolean isDeviceOwnerUserId(int userId) {
-        return mDeviceOwner != null && mDeviceOwnerUserId == userId;
+        synchronized (mLock) {
+            return mDeviceOwner != null && mDeviceOwnerUserId == userId;
+        }
     }
 
     boolean hasProfileOwner(int userId) {
-        return getProfileOwnerComponent(userId) != null;
+        synchronized (mLock) {
+            return getProfileOwnerComponent(userId) != null;
+        }
     }
 
     /**
      * @return true if user restrictions need to be migrated for DO.
      */
     boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
-        return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
+        synchronized (mLock) {
+            return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
+        }
     }
 
     /**
      * @return true if user restrictions need to be migrated for PO.
      */
     boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        return profileOwner != null && !profileOwner.userRestrictionsMigrated;
+        synchronized (mLock) {
+            OwnerInfo profileOwner = mProfileOwners.get(userId);
+            return profileOwner != null && !profileOwner.userRestrictionsMigrated;
+        }
     }
 
     /** Sets the user restrictions migrated flag, and also writes to the file. */
     void setDeviceOwnerUserRestrictionsMigrated() {
-        if (mDeviceOwner != null) {
-            mDeviceOwner.userRestrictionsMigrated = true;
+        synchronized (mLock) {
+            if (mDeviceOwner != null) {
+                mDeviceOwner.userRestrictionsMigrated = true;
+            }
+            writeDeviceOwner();
         }
-        writeDeviceOwner();
     }
 
     /** Sets the remote bugreport uri and hash, and also writes to the file. */
     void setDeviceOwnerRemoteBugreportUriAndHash(String remoteBugreportUri,
             String remoteBugreportHash) {
-        if (mDeviceOwner != null) {
-            mDeviceOwner.remoteBugreportUri = remoteBugreportUri;
-            mDeviceOwner.remoteBugreportHash = remoteBugreportHash;
+        synchronized (mLock) {
+            if (mDeviceOwner != null) {
+                mDeviceOwner.remoteBugreportUri = remoteBugreportUri;
+                mDeviceOwner.remoteBugreportHash = remoteBugreportHash;
+            }
+            writeDeviceOwner();
         }
-        writeDeviceOwner();
     }
 
     /** Sets the user restrictions migrated flag, and also writes to the file.  */
     void setProfileOwnerUserRestrictionsMigrated(int userId) {
-        OwnerInfo profileOwner = mProfileOwners.get(userId);
-        if (profileOwner != null) {
-            profileOwner.userRestrictionsMigrated = true;
+        synchronized (mLock) {
+            OwnerInfo profileOwner = mProfileOwners.get(userId);
+            if (profileOwner != null) {
+                profileOwner.userRestrictionsMigrated = true;
+            }
+            writeProfileOwner(userId);
         }
-        writeProfileOwner(userId);
     }
 
-    private boolean readLegacyOwnerFile(File file) {
+    private boolean readLegacyOwnerFileLocked(File file) {
         if (!file.exists()) {
             // Already migrated or the device has no owners.
             return false;
@@ -363,7 +451,7 @@
     }
 
     void writeDeviceOwner() {
-        synchronized (this) {
+        synchronized (mLock) {
             if (DEBUG) {
                 Log.d(TAG, "Writing to device owner file");
             }
@@ -372,7 +460,7 @@
     }
 
     void writeProfileOwner(int userId) {
-        synchronized (this) {
+        synchronized (mLock) {
             if (DEBUG) {
                 Log.d(TAG, "Writing to profile owner file for user " + userId);
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 107de8b..b21f5fb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -181,7 +181,7 @@
      * visual content.
      */
     private static final int DEFAULT_SYSTEM_THEME =
-            com.android.internal.R.style.Theme_DeviceDefault_Light_DarkActionBar;
+            com.android.internal.R.style.Theme_DeviceDefault_System;
 
     private final int mFactoryTestMode;
     private Timer mProfilerSnapshotTimer;
diff --git a/services/tests/servicestests/src/com/android/server/Vector3Test.java b/services/tests/servicestests/src/com/android/server/Vector3Test.java
new file mode 100644
index 0000000..88dbe70
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/Vector3Test.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 android.test.AndroidTestCase;
+
+import java.lang.Exception;
+import java.lang.Math;
+
+/**
+ * Tests for {@link com.android.server.AnyMotionDetector.Vector3}
+ */
+public class Vector3Test extends AndroidTestCase {
+    private static final float tolerance = 1.0f / (1 << 12);
+    private static final float STATIONARY_ANGLE_THRESHOLD = 0.05f;
+
+    private AnyMotionDetector.Vector3 unitXAxis;
+    private AnyMotionDetector.Vector3 unitYAxis;
+    private AnyMotionDetector.Vector3 unitZAxis;
+    private AnyMotionDetector.Vector3 x3;
+    private AnyMotionDetector.Vector3 case1A;
+    private AnyMotionDetector.Vector3 case1B;
+    private AnyMotionDetector.Vector3 case2A;
+    private AnyMotionDetector.Vector3 case2B;
+    private AnyMotionDetector.Vector3 x1y1;
+    private AnyMotionDetector.Vector3 xn1y1;
+    private AnyMotionDetector.Vector3 x1z1;
+    private AnyMotionDetector.Vector3 y1z1;
+    private AnyMotionDetector.Vector3 piOverSixUnitCircle;
+
+
+    private boolean nearlyEqual(float a, float b) {
+        return Math.abs(a - b) <= tolerance;
+    }
+
+    public void setUp() throws Exception {
+        super.setUp();
+        unitXAxis = new AnyMotionDetector.Vector3(0, 1, 0, 0);
+        unitYAxis = new AnyMotionDetector.Vector3(0, 0, 1, 0);
+        unitZAxis = new AnyMotionDetector.Vector3(0, 0, 0, 1);
+        x3 = new AnyMotionDetector.Vector3(0, 3, 0, 0);
+        x1y1 = new AnyMotionDetector.Vector3(0, 1, 1, 0);
+        xn1y1 = new AnyMotionDetector.Vector3(0, -1, 1, 0);
+        x1z1 = new AnyMotionDetector.Vector3(0, 1, 0, 1);
+        y1z1 = new AnyMotionDetector.Vector3(0, 0, 1, 1);
+        piOverSixUnitCircle = new AnyMotionDetector.Vector3(
+                0, (float)Math.sqrt(3)/2, (float)0.5, 0);
+
+        case1A = new AnyMotionDetector.Vector3(0, -9.81f, -0.02f, 0.3f);
+        case1B = new AnyMotionDetector.Vector3(0, -9.80f, -0.02f, 0.3f);
+        case2A = new AnyMotionDetector.Vector3(0, 1f, 2f, 3f);
+        case2B = new AnyMotionDetector.Vector3(0, 4f, 5f, 6f);
+    }
+
+    public void testVector3Norm() {
+        assertTrue(nearlyEqual(unitXAxis.norm(), 1.0f));
+        assertTrue(nearlyEqual(unitYAxis.norm(), 1.0f));
+        assertTrue(nearlyEqual(unitZAxis.norm(), 1.0f));
+        assertTrue(nearlyEqual(x1y1.norm(), (float)Math.sqrt(2)));
+    }
+
+    public void testVector3AngleBetween() {
+        // Zero angle.
+        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitXAxis), 0.0f));
+        assertTrue(nearlyEqual(unitYAxis.angleBetween(unitYAxis), 0.0f));
+        assertTrue(nearlyEqual(unitZAxis.angleBetween(unitZAxis), 0.0f));
+
+        // Unit axes should be perpendicular.
+        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitYAxis), 90.0f));
+        assertTrue(nearlyEqual(unitXAxis.angleBetween(unitZAxis), 90.0f));
+        assertTrue(nearlyEqual(unitYAxis.angleBetween(unitZAxis), 90.0f));
+
+        // 45 degree angles.
+        assertTrue(nearlyEqual(unitXAxis.angleBetween(x1y1), 45.0f));
+        assertTrue(nearlyEqual(unitYAxis.angleBetween(x1y1), 45.0f));
+
+        // 135 degree angles.
+        assertTrue(nearlyEqual(xn1y1.angleBetween(unitXAxis), 135.0f));
+
+        // 30 degree angles.
+        assertTrue(nearlyEqual(piOverSixUnitCircle.angleBetween(unitXAxis), 30.0f));
+
+        // These vectors are expected to be still.
+        assertTrue(case1A.angleBetween(case1A) < STATIONARY_ANGLE_THRESHOLD);
+        assertTrue(case1A.angleBetween(case1B) < STATIONARY_ANGLE_THRESHOLD);
+        assertTrue(unitXAxis.angleBetween(unitXAxis) < STATIONARY_ANGLE_THRESHOLD);
+        assertTrue(unitYAxis.angleBetween(unitYAxis) < STATIONARY_ANGLE_THRESHOLD);
+        assertTrue(unitZAxis.angleBetween(unitZAxis) < STATIONARY_ANGLE_THRESHOLD);
+    }
+
+    public void testVector3Normalized() {
+        AnyMotionDetector.Vector3 unitXAxisNormalized = unitXAxis.normalized();
+        assertTrue(nearlyEqual(unitXAxisNormalized.x, unitXAxis.x));
+        assertTrue(nearlyEqual(unitXAxisNormalized.y, unitXAxis.y));
+        assertTrue(nearlyEqual(unitXAxisNormalized.z, unitXAxis.z));
+
+        // Normalizing the vector created by multiplying the unit vector by 3 gets the unit vector.
+        AnyMotionDetector.Vector3 x3Normalized = x3.normalized();
+        assertTrue(nearlyEqual(x3Normalized.x, unitXAxis.x));
+        assertTrue(nearlyEqual(x3Normalized.y, unitXAxis.y));
+        assertTrue(nearlyEqual(x3Normalized.z, unitXAxis.z));
+    }
+
+    public void testVector3Cross() {
+        AnyMotionDetector.Vector3 xCrossX = unitXAxis.cross(unitXAxis);
+        assertTrue(nearlyEqual(xCrossX.x, 0f));
+        assertTrue(nearlyEqual(xCrossX.y, 0f));
+        assertTrue(nearlyEqual(xCrossX.z, 0f));
+
+        AnyMotionDetector.Vector3 xCrossNx = unitXAxis.cross(unitXAxis.times(-1));
+        assertTrue(nearlyEqual(xCrossNx.x, 0f));
+        assertTrue(nearlyEqual(xCrossNx.y, 0f));
+        assertTrue(nearlyEqual(xCrossNx.z, 0f));
+
+        AnyMotionDetector.Vector3 cross2 = case2A.cross(case2B);
+        assertTrue(nearlyEqual(cross2.x, -3));
+        assertTrue(nearlyEqual(cross2.y, 6));
+        assertTrue(nearlyEqual(cross2.z, -3));
+    }
+
+     public void testVector3Times() {
+         AnyMotionDetector.Vector3 yTimes2 = unitYAxis.times(2);
+         assertTrue(nearlyEqual(yTimes2.x, 0f));
+         assertTrue(nearlyEqual(yTimes2.y, 2f));
+         assertTrue(nearlyEqual(yTimes2.z, 0f));
+     }
+
+     public void testVector3Plus() {
+         AnyMotionDetector.Vector3 xPlusY = unitXAxis.plus(unitYAxis);
+         assertTrue(nearlyEqual(xPlusY.x, 1f));
+         assertTrue(nearlyEqual(xPlusY.y, 1f));
+         assertTrue(nearlyEqual(xPlusY.z, 0f));
+     }
+
+     public void testVector3Minus() {
+         AnyMotionDetector.Vector3 xMinusY = unitXAxis.minus(unitYAxis);
+         assertTrue(nearlyEqual(xMinusY.x, 1f));
+         assertTrue(nearlyEqual(xMinusY.y, -1f));
+         assertTrue(nearlyEqual(xMinusY.z, 0f));
+     }
+
+     public void testVector3DotProduct() {
+         float xDotX = unitXAxis.dotProduct(unitXAxis);
+         float xDotY = unitXAxis.dotProduct(unitYAxis);
+         float xDotZ = unitXAxis.dotProduct(unitZAxis);
+         assertTrue(nearlyEqual(xDotX, 1f));
+         assertTrue(nearlyEqual(xDotY, 0f));
+         assertTrue(nearlyEqual(xDotZ, 0f));
+     }
+}
diff --git a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index 30a7dbc..a30b362 100644
--- a/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/services/tests/servicestests/src/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -16,8 +16,6 @@
 
 package com.android.server.connectivity.tethering;
 
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.inOrder;
@@ -26,6 +24,14 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static android.net.ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
+import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
+import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
+
 import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
 import android.net.InterfaceConfiguration;
@@ -78,8 +84,7 @@
         when(mNMService.getInterfaceConfig(IFACE_NAME)).thenReturn(mInterfaceConfiguration);
     }
 
-    @Before
-    public void setUp() throws Exception {
+    @Before public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
     }
 
@@ -89,10 +94,8 @@
                 ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper);
         mTestedSm.start();
         mLooper.dispatchAll();
-        assertTrue("Should start out available for tethering", mTestedSm.isAvailable());
-        assertFalse("Should not be tethered initially", mTestedSm.isTethered());
-        assertFalse("Should have no errors initially", mTestedSm.isErrored());
-        verify(mTetherHelper).sendTetherStateChangedBroadcast();
+        verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mTetherHelper, mNMService, mStatsService);
     }
 
@@ -119,28 +122,23 @@
     @Test
     public void handlesImmediateInterfaceDown() throws Exception {
         initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+
         dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-        verify(mTetherHelper).sendTetherStateChangedBroadcast();
+        verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertFalse("Should not be tetherable when the interface is down", mTestedSm.isAvailable());
-        assertFalse("Should not be tethered when the interface is down", mTestedSm.isTethered());
-        assertFalse("Should have no errors when the interface goes immediately down",
-                mTestedSm.isErrored());
     }
 
     @Test
     public void canBeTethered() throws Exception {
         initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
         InOrder inOrder = inOrder(mTetherHelper, mNMService);
-        inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(true, mTestedSm);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).sendTetherStateChangedBroadcast();
-
+        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertFalse("Should not be tetherable when tethered", mTestedSm.isAvailable());
-        assertTrue("Should be in a tethered state", mTestedSm.isTethered());
-        assertFalse("Should have no errors when tethered", mTestedSm.isErrored());
     }
 
     @Test
@@ -149,13 +147,10 @@
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
-        inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(false, mTestedSm);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).sendTetherStateChangedBroadcast();
+        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertTrue("Should be ready for tethering again", mTestedSm.isAvailable());
-        assertFalse("Should not be tethered", mTestedSm.isTethered());
-        assertFalse("Should have no errors", mTestedSm.isErrored());
     }
 
     @Test
@@ -164,16 +159,12 @@
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
         InOrder inOrder = inOrder(mTetherHelper, mNMService);
-        inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(true, mTestedSm);
         inOrder.verify(mNMService).getInterfaceConfig(IFACE_NAME);
         inOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
         inOrder.verify(mNMService).tetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).sendTetherStateChangedBroadcast();
-
+        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_TETHERED, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertFalse("Should not be tetherable when tethered", mTestedSm.isAvailable());
-        assertTrue("Should be in a tethered state", mTestedSm.isTethered());
-        assertFalse("Should have no errors when tethered", mTestedSm.isErrored());
     }
 
     @Test
@@ -186,9 +177,6 @@
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertFalse("Should not be tetherable when tethered", mTestedSm.isAvailable());
-        assertTrue("Should be in a tethered state", mTestedSm.isTethered());
-        assertFalse("Should have no errors when tethered", mTestedSm.isErrored());
     }
 
     @Test
@@ -203,9 +191,6 @@
         inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
         inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertFalse("Should not be tetherable when tethered", mTestedSm.isAvailable());
-        assertTrue("Should be in a tethered state", mTestedSm.isTethered());
-        assertFalse("Should have no errors when tethered", mTestedSm.isErrored());
     }
 
     @Test
@@ -214,16 +199,13 @@
 
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
         InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
-        inOrder.verify(mTetherHelper).notifyInterfaceTetheringReadiness(false, mTestedSm);
         inOrder.verify(mStatsService).forceUpdate();
         inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
         inOrder.verify(mNMService).untetherInterface(IFACE_NAME);
-        inOrder.verify(mTetherHelper).sendTetherStateChangedBroadcast();
+        inOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR);
         verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
-        assertTrue("Should be ready for tethering again", mTestedSm.isAvailable());
-        assertFalse("Should not be tethered", mTestedSm.isTethered());
-        assertFalse("Should have no errors", mTestedSm.isErrored());
     }
 
     @Test
@@ -235,13 +217,12 @@
                 doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
             }
             dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
-            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration);
+            InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
             usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
             usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                     IFACE_NAME, mInterfaceConfiguration);
-            verify(mTetherHelper).notifyInterfaceTetheringReadiness(false, mTestedSm);
-            assertFalse("Should not be available", mTestedSm.isAvailable());
-            assertFalse("Should not be tethered", mTestedSm.isTethered());
+            usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                    IFACE_NAME, mTestedSm, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR);
         }
     }
 
@@ -251,15 +232,12 @@
 
         doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
         dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(
                 IFACE_NAME, mInterfaceConfiguration);
-        // Initial call is when we transition to the tethered state on request.
-        verify(mTetherHelper).notifyInterfaceTetheringReadiness(true, mTestedSm);
-        // And this call is to notify that we really aren't requested tethering.
-        verify(mTetherHelper).notifyInterfaceTetheringReadiness(false, mTestedSm);
-        assertTrue("Expected to see an error reported", mTestedSm.isErrored());
+        usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_TETHER_IFACE_ERROR);
     }
 
     @Test
@@ -268,10 +246,11 @@
 
         doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
         dispatchTetherConnectionChanged(UPSTREAM_IFACE);
-        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration);
+        InOrder usbTeardownOrder = inOrder(mNMService, mInterfaceConfiguration, mTetherHelper);
         usbTeardownOrder.verify(mInterfaceConfiguration).setInterfaceDown();
         usbTeardownOrder.verify(mNMService).setInterfaceConfig(IFACE_NAME, mInterfaceConfiguration);
-        verify(mTetherHelper).notifyInterfaceTetheringReadiness(false, mTestedSm);
+        usbTeardownOrder.verify(mTetherHelper).notifyInterfaceStateChange(
+                IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
     }
 
     /**
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index 744443f..6cb4a82 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -28,10 +28,8 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.UserManagerInternal;
-import android.os.storage.StorageManager;
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
-import android.util.Log;
 import android.util.Pair;
 import android.view.IWindowManager;
 
@@ -57,7 +55,7 @@
         private final File mProfileOwnerBase;
 
         public OwnersTestable(DpmMockContext context) {
-            super(context, context.userManager, context.userManagerInternal);
+            super(context.userManager, context.userManagerInternal, context.packageManagerInternal);
             mLegacyFile = new File(context.dataDir, LEGACY_FILE);
             mDeviceOwnerFile = new File(context.dataDir, DEVICE_OWNER_FILE);
             mProfileOwnerBase = new File(context.dataDir, PROFILE_OWNER_FILE_BASE);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 8ce7304..2f11967 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -697,6 +697,10 @@
         return getInstrumentation().getContext();
     }
 
+    protected ShortcutManager getManager() {
+        return mManager;
+    }
+
     protected void deleteAllSavedFiles() {
         // Empty the data directory.
         if (mInjectedFilePathRoot.exists()) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index 399fddf..ea44462 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -56,35 +56,78 @@
     // ShortcutInfo tests
 
     public void testShortcutInfoMissingMandatoryFields() {
+        // Disable throttling.
+        mService.updateConfigurationLocked(
+                ShortcutService.ConfigConstants.KEY_MAX_UPDATES_PER_INTERVAL + "=99999999,"
+                + ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=99999999"
+        );
+
         assertExpectException(
                 IllegalArgumentException.class,
                 "ID must be provided",
                 () -> new ShortcutInfo.Builder(getTestContext()).build());
-        assertExpectException(
-                NullPointerException.class,
-                "Intent action must be set",
+
+        assertExpectException(NullPointerException.class, "Intent action must be set",
                 () -> new ShortcutInfo.Builder(getTestContext()).setIntent(new Intent()));
+
+        assertExpectException(NullPointerException.class, "Activity must be provided", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext()).setId("id").build();
+            assertTrue(getManager().setDynamicShortcuts(list(si)));
+        });
+
         assertExpectException(
-                NullPointerException.class,
-                "activity must be provided",
-                () -> new ShortcutInfo.Builder(getTestContext()).setId("id").build()
-                        .enforceMandatoryFields());
+                IllegalArgumentException.class, "Short label must be provided", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
+                    .build();
+            assertTrue(getManager().setDynamicShortcuts(list(si)));
+        });
+
         assertExpectException(
-                IllegalArgumentException.class,
-                "title must be provided",
-                () -> new ShortcutInfo.Builder(getTestContext()).setId("id")
-                        .setActivity(
-                                new ComponentName(getTestContext().getPackageName(), "s"))
-                        .build()
-                        .enforceMandatoryFields());
+                IllegalArgumentException.class, "Short label must be provided", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
+                    .build();
+            assertTrue(getManager().addDynamicShortcuts(list(si)));
+        });
+
+        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
+                    .setShortLabel("x")
+                    .build();
+            assertTrue(getManager().setDynamicShortcuts(list(si)));
+        });
+
+        assertExpectException(NullPointerException.class, "Intent must be provided", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName(getTestContext().getPackageName(), "s"))
+                    .setShortLabel("x")
+                    .build();
+            assertTrue(getManager().addDynamicShortcuts(list(si)));
+        });
+
         assertExpectException(
-                NullPointerException.class,
-                "Intent must be provided",
-                () -> new ShortcutInfo.Builder(getTestContext()).setId("id")
-                        .setActivity(
-                                new ComponentName(getTestContext().getPackageName(), "s"))
-                        .setTitle("x").build()
-                        .enforceMandatoryFields());
+                IllegalStateException.class, "package name mismatch", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName("xxx", "s"))
+                    .build();
+            assertTrue(getManager().setDynamicShortcuts(list(si)));
+        });
+
+        assertExpectException(
+                IllegalStateException.class, "package name mismatch", () -> {
+            ShortcutInfo si = new ShortcutInfo.Builder(getTestContext())
+                    .setId("id")
+                    .setActivity(new ComponentName("xxx", "s"))
+                    .build();
+            assertTrue(getManager().addDynamicShortcuts(list(si)));
+        });
     }
 
     public void testShortcutInfoParcel() {
diff --git a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
index 71878fd..04c7a04 100644
--- a/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
+++ b/services/tests/shortcutmanagerutils/src/com/android/server/pm/shortcutmanagertest/ShortcutManagerTestUtils.java
@@ -289,8 +289,6 @@
             String expectedExceptionMessageRegex, Runnable r) {
         try {
             r.run();
-            Assert.fail("Expected exception type " + expectedExceptionType.getName()
-                    + " was not thrown (message=" + message + ")");
         } catch (Throwable e) {
             Assert.assertTrue(
                     "Expected exception type was " + expectedExceptionType.getName()
@@ -299,7 +297,10 @@
             if (expectedExceptionMessageRegex != null) {
                 MoreAsserts.assertContainsRegex(expectedExceptionMessageRegex, e.getMessage());
             }
+            return; // Pass
         }
+        Assert.fail("Expected exception type " + expectedExceptionType.getName()
+                + " was not thrown");
     }
 
     public static List<ShortcutInfo> assertShortcutIds(List<ShortcutInfo> actualShortcuts,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
index 0f68cca..50c5d5d 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/DatabaseHelper.java
@@ -40,11 +40,12 @@
     static final boolean DBG = false;
 
     private static final String NAME = "sound_model.db";
-    private static final int VERSION = 4;
+    private static final int VERSION = 5;
 
     public static interface SoundModelContract {
         public static final String TABLE = "sound_model";
         public static final String KEY_MODEL_UUID = "model_uuid";
+        public static final String KEY_VENDOR_UUID = "vendor_uuid";
         public static final String KEY_KEYPHRASE_ID = "keyphrase_id";
         public static final String KEY_TYPE = "type";
         public static final String KEY_DATA = "data";
@@ -58,6 +59,7 @@
     private static final String CREATE_TABLE_SOUND_MODEL = "CREATE TABLE "
             + SoundModelContract.TABLE + "("
             + SoundModelContract.KEY_MODEL_UUID + " TEXT PRIMARY KEY,"
+            + SoundModelContract.KEY_VENDOR_UUID + " TEXT, "
             + SoundModelContract.KEY_KEYPHRASE_ID + " INTEGER,"
             + SoundModelContract.KEY_TYPE + " INTEGER,"
             + SoundModelContract.KEY_DATA + " BLOB,"
@@ -78,9 +80,19 @@
 
     @Override
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
-        // TODO: For now, drop older tables and recreate new ones.
-        db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
-        onCreate(db);
+        if (oldVersion < 4) {
+            // For old versions just drop the tables and recreate new ones.
+            db.execSQL("DROP TABLE IF EXISTS " + SoundModelContract.TABLE);
+            onCreate(db);
+        } else {
+            // In the jump to version 5, we added support for the vendor UUID.
+            if (oldVersion == 4) {
+                Slog.d(TAG, "Adding vendor UUID column");
+                db.execSQL("ALTER TABLE " + SoundModelContract.TABLE + " ADD COLUMN "
+                        + SoundModelContract.KEY_VENDOR_UUID + " TEXT");
+                oldVersion++;
+            }
+        }
     }
 
     /**
@@ -93,6 +105,7 @@
             SQLiteDatabase db = getWritableDatabase();
             ContentValues values = new ContentValues();
             values.put(SoundModelContract.KEY_MODEL_UUID, soundModel.uuid.toString());
+            values.put(SoundModelContract.KEY_VENDOR_UUID, soundModel.vendorUuid.toString());
             values.put(SoundModelContract.KEY_TYPE, SoundTrigger.SoundModel.TYPE_KEYPHRASE);
             values.put(SoundModelContract.KEY_DATA, soundModel.data);
 
@@ -176,6 +189,11 @@
                             continue;
                         }
 
+                        String vendorUuidString = null;
+                        int vendorUuidColumn = c.getColumnIndex(SoundModelContract.KEY_VENDOR_UUID);
+                        if (vendorUuidColumn != -1) {
+                            vendorUuidString = c.getString(vendorUuidColumn);
+                        }
                         byte[] data = c.getBlob(c.getColumnIndex(SoundModelContract.KEY_DATA));
                         int recognitionModes = c.getInt(
                                 c.getColumnIndex(SoundModelContract.KEY_RECOGNITION_MODES));
@@ -212,9 +230,12 @@
                         Keyphrase[] keyphrases = new Keyphrase[1];
                         keyphrases[0] = new Keyphrase(
                                 keyphraseId, recognitionModes, modelLocale, text, users);
+                        UUID vendorUuid = null;
+                        if (vendorUuidString != null) {
+                            vendorUuid = UUID.fromString(vendorUuidString);
+                        }
                         KeyphraseSoundModel model = new KeyphraseSoundModel(
-                                UUID.fromString(modelUuid),
-                                null /* FIXME use vendor UUID */, data, keyphrases);
+                                UUID.fromString(modelUuid), vendorUuid, data, keyphrases);
                         if (DBG) {
                             Slog.d(TAG, "Found SoundModel for the given keyphrase/locale/user: "
                                     + model);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3316bc8..c96f7c0 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -396,6 +396,12 @@
      */
     public static final String EVENT_CALL_PULL_FAILED = "android.telecom.event.CALL_PULL_FAILED";
 
+    /**
+     * Connection event used to inform {@link InCallService}s when the merging of two calls has
+     * failed. The User Interface should use this message to inform the user of the error.
+     */
+    public static final String EVENT_CALL_MERGE_FAILED = "android.telecom.event.CALL_MERGE_FAILED";
+
     // Flag controlling whether PII is emitted into the logs
     private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index af15c0a..44d89c1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -759,6 +759,24 @@
     public static final String KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT =
             "duration_blocking_disabled_after_emergency_int";
 
+    /**
+     * @hide
+     * The default value for preferred CDMA roaming mode (aka CDMA system select.)
+     *          CDMA_ROAMING_MODE_RADIO_DEFAULT = the default roaming mode from the radio
+     *          CDMA_ROAMING_MODE_HOME = Home Networks
+     *          CDMA_ROAMING_MODE_AFFILIATED = Roaming on Affiliated networks
+     *          CDMA_ROAMING_MODE_ANY = Roaming on any networks
+     */
+    public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
+    /** @hide */
+    public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1;
+    /** @hide */
+    public static final int CDMA_ROAMING_MODE_HOME = 0;
+    /** @hide */
+    public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
+    /** @hide */
+    public static final int CDMA_ROAMING_MODE_ANY = 2;
+
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
 
@@ -897,6 +915,7 @@
         sDefaults.putString(KEY_MMS_USER_AGENT_STRING, "");
         sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
         sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
+        sDefaults.putInt(KEY_CDMA_ROAMING_MODE_INT, CDMA_ROAMING_MODE_RADIO_DEFAULT);
 
         // Carrier Signalling Receivers
         sDefaults.putStringArray(KEY_SIGNAL_REDIRECTION_RECEIVER_STRING_ARRAY, null);
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index e4981ce..8166e00 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -104,6 +104,7 @@
     public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42;
     public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 43;
     public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
+    public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 49a7672..0168874 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -432,7 +432,10 @@
      * The intent will have the following extra values:</p>
      * <ul>
      *   <li>apnType</li><dd>A string with the apn type.</dd>
-     *   <li>pcoValue</li><dd>A integer read from modem.</dd>
+     *   <li>apnProto</li><dd>A string with the protocol of the apn connection (IP,IPV6,
+     *                        IPV4V6)</dd>
+     *   <li>pcoId</li><dd>An integer indicating the pco id for the data.</dd>
+     *   <li>pcoValue</li><dd>A byte array of pco data read from modem.</dd>
      *   <li>subId</dt><li>Sub Id which associated the data connection.</dd>
      * </ul>
      * <p class="note">This is a protected intent that can only be sent by the system. </p>
@@ -444,7 +447,9 @@
     public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
     public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
     public static final String EXTRA_APN_TYPE_KEY = "apnType";
-    public static final String EXTRA_PCO_KEY = "pco";
+    public static final String EXTRA_APN_PROTO_KEY = "apnProto";
+    public static final String EXTRA_PCO_ID_KEY = "pcoId";
+    public static final String EXTRA_PCO_VALUE_KEY = "pcoValue";
 
 
    /**