Merge "[Fix extra data in cache]" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index 5d28d2c..6110d1c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -32174,7 +32174,6 @@
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34094,6 +34093,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyGenParameterSpec.Builder {
@@ -34116,6 +34116,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
@@ -34135,6 +34136,7 @@
     method public boolean isInsideSecureHardware();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34197,6 +34199,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyProtection.Builder {
@@ -34212,6 +34215,7 @@
     method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index a2943ff..c01f1c3 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -34661,7 +34661,6 @@
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -36583,6 +36582,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyGenParameterSpec.Builder {
@@ -36605,6 +36605,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
@@ -36624,6 +36625,7 @@
     method public boolean isInsideSecureHardware();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -36686,6 +36688,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyProtection.Builder {
@@ -36701,6 +36704,7 @@
     method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index d42c18c..96d29d1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -32187,7 +32187,6 @@
     field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
     field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
     field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS";
-    field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
     field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
     field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
     field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS";
@@ -34109,6 +34108,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyGenParameterSpec.Builder {
@@ -34131,6 +34131,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
@@ -34150,6 +34151,7 @@
     method public boolean isInsideSecureHardware();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationRequirementEnforcedBySecureHardware();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public class KeyNotYetValidException extends java.security.InvalidKeyException {
@@ -34212,6 +34214,7 @@
     method public boolean isDigestsSpecified();
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isUserAuthenticationRequired();
+    method public boolean isUserAuthenticationValidWhileOnBody();
   }
 
   public static final class KeyProtection.Builder {
@@ -34227,6 +34230,7 @@
     method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 3385a17..980329f 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -807,8 +807,6 @@
     }
 
     /**
-     * AnimatorSet is only reversible when the set contains no sequential animation, and no child
-     * animators have a start delay.
      * @hide
      */
     @Override
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 35b7c39..52631d1 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -263,8 +263,8 @@
      * The view that will represent this notification in the notification list (which is pulled
      * down from the status bar).
      *
-     * As of N, this field is not used. The notification view is determined by the inputs to
-     * {@link Notification.Builder}; a custom RemoteViews can optionally be
+     * As of N, this field may be null. The notification view is determined by the inputs
+     * to {@link Notification.Builder}; a custom RemoteViews can optionally be
      * supplied with {@link Notification.Builder#setCustomContentView(RemoteViews)}.
      */
     @Deprecated
@@ -275,7 +275,7 @@
      * opportunity to show more detail. The system UI may choose to show this
      * instead of the normal content view at its discretion.
      *
-     * As of N, this field is not used. The expanded notification view is determined by the
+     * As of N, this field may be null. The expanded notification view is determined by the
      * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
      * supplied with {@link Notification.Builder#setCustomBigContentView(RemoteViews)}.
      */
@@ -289,7 +289,7 @@
      * choose to show this as a heads-up notification, which will pop up so the user can see
      * it without leaving their current activity.
      *
-     * As of N, this field is not used. The heads-up notification view is determined by the
+     * As of N, this field may be null. The heads-up notification view is determined by the
      * inputs to {@link Notification.Builder}; a custom RemoteViews can optionally be
      * supplied with {@link Notification.Builder#setCustomHeadsUpContentView(RemoteViews)}.
      */
@@ -2129,8 +2129,23 @@
      * </pre>
      */
     public static class Builder {
+        /**
+         * @hide
+         */
+        public static final String EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT =
+                "android.rebuild.contentViewActionCount";
+        /**
+         * @hide
+         */
+        public static final String EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT
+                = "android.rebuild.bigViewActionCount";
+        /**
+         * @hide
+         */
+        public static final String EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT
+                = "android.rebuild.hudViewActionCount";
+
         private static final int MAX_ACTION_BUTTONS = 3;
-        private static final float LARGE_TEXT_SCALE = 1.3f;
 
         private Context mContext;
         private Notification mN;
@@ -3566,19 +3581,6 @@
             return null;
         }
 
-        private void setBuilderContentView(Notification n, RemoteViews contentView) {
-            n.contentView = contentView;
-        }
-
-        private void setBuilderBigContentView(Notification n, RemoteViews bigContentView) {
-            n.bigContentView = bigContentView;
-        }
-
-        private void setBuilderHeadsUpContentView(Notification n,
-                RemoteViews headsUpContentView) {
-            n.headsUpContentView = headsUpContentView;
-        }
-
         /**
          * @deprecated Use {@link #build()} instead.
          */
@@ -3606,6 +3608,28 @@
                 mStyle.buildStyled(mN);
             }
 
+            if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+                if (mN.contentView == null) {
+                    mN.contentView = makeContentView();
+                    mN.extras.putInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT,
+                            mN.contentView.getSequenceNumber());
+                }
+                if (mN.bigContentView == null) {
+                    mN.bigContentView = makeBigContentView();
+                    if (mN.bigContentView != null) {
+                        mN.extras.putInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT,
+                                mN.bigContentView.getSequenceNumber());
+                    }
+                }
+                if (mN.headsUpContentView == null) {
+                    mN.headsUpContentView = makeHeadsUpContentView();
+                    if (mN.headsUpContentView != null) {
+                        mN.extras.putInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT,
+                                mN.headsUpContentView.getSequenceNumber());
+                    }
+                }
+            }
+
             if ((mN.defaults & DEFAULT_LIGHTS) != 0) {
                 mN.flags |= FLAG_SHOW_LIGHTS;
             }
@@ -3623,6 +3647,40 @@
             return n;
         }
 
+        /**
+         * @hide
+         */
+        public static void stripForDelivery(Notification n) {
+            String templateClass = n.extras.getString(EXTRA_TEMPLATE);
+            if (TextUtils.isEmpty(templateClass)) {
+                return;
+            }
+            // Only strip views for known Styles because we won't know how to
+            // re-create them otherwise.
+            if (getNotificationStyleClass(templateClass) == null) {
+                return;
+            }
+            // Get rid of unmodified BuilderRemoteViews.
+            if (n.contentView instanceof BuilderRemoteViews &&
+                    n.extras.getInt(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT, -1) ==
+                            n.contentView.getSequenceNumber()) {
+                n.contentView = null;
+                n.extras.remove(EXTRA_REBUILD_CONTENT_VIEW_ACTION_COUNT);
+            }
+            if (n.bigContentView instanceof BuilderRemoteViews &&
+                    n.extras.getInt(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT, -1) ==
+                            n.bigContentView.getSequenceNumber()) {
+                n.bigContentView = null;
+                n.extras.remove(EXTRA_REBUILD_BIG_CONTENT_VIEW_ACTION_COUNT);
+            }
+            if (n.headsUpContentView instanceof BuilderRemoteViews &&
+                    n.extras.getInt(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT, -1) ==
+                            n.headsUpContentView.getSequenceNumber()) {
+                n.headsUpContentView = null;
+                n.extras.remove(EXTRA_REBUILD_HEADS_UP_CONTENT_VIEW_ACTION_COUNT);
+            }
+        }
+
         private int getBaseLayoutResource() {
             return R.layout.notification_template_material_base;
         }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 1f17024..ff2cfd6 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -246,6 +246,7 @@
         }
         if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
         final Notification copy = notification.clone();
+        Builder.stripForDelivery(copy);
         try {
             service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                     copy, idOut, user.getIdentifier());
diff --git a/core/java/android/net/BaseDhcpStateMachine.java b/core/java/android/net/BaseDhcpStateMachine.java
deleted file mode 100644
index a25847d..0000000
--- a/core/java/android/net/BaseDhcpStateMachine.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import com.android.internal.util.StateMachine;
-
-/**
- * Interface that must be implemented by DHCP state machines.
- *
- * This is an abstract class instead of a Java interface so that callers can just declare an object
- * of this type and be able to call all the methods defined by either StateMachine or this class.
- *
- * @hide
- */
-public abstract class BaseDhcpStateMachine extends StateMachine {
-    protected BaseDhcpStateMachine(String tag) {
-        super(tag);
-    }
-    public abstract void registerForPreDhcpNotification();
-    public abstract void doQuit();
-}
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
deleted file mode 100644
index 73ef78e..0000000
--- a/core/java/android/net/DhcpStateMachine.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.DhcpResults;
-import android.net.NetworkUtils;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.Log;
-
-/**
- * StateMachine that interacts with the native DHCP client and can talk to
- * a controller that also needs to be a StateMachine
- *
- * The DhcpStateMachine provides the following features:
- * - Wakeup and renewal using the native DHCP client  (which will not renew
- *   on its own when the device is in suspend state and this can lead to device
- *   holding IP address beyond expiry)
- * - A notification right before DHCP request or renewal is started. This
- *   can be used for any additional setup before DHCP. For example, wifi sets
- *   BT-Wifi coex settings right before DHCP is initiated
- *
- * @hide
- */
-public class DhcpStateMachine extends BaseDhcpStateMachine {
-
-    private static final String TAG = "DhcpStateMachine";
-    private static final boolean DBG = false;
-
-
-    /* A StateMachine that controls the DhcpStateMachine */
-    private StateMachine mController;
-
-    private Context mContext;
-    private BroadcastReceiver mBroadcastReceiver;
-    private AlarmManager mAlarmManager;
-    private PendingIntent mDhcpRenewalIntent;
-    private PowerManager.WakeLock mDhcpRenewWakeLock;
-    private static final String WAKELOCK_TAG = "DHCP";
-
-    //Remember DHCP configuration from first request
-    private DhcpResults mDhcpResults;
-
-    private static final int DHCP_RENEW = 0;
-    private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
-
-    //Used for sanity check on setting up renewal
-    private static final int MIN_RENEWAL_TIME_SECS = 5 * 60;  // 5 minutes
-
-    private final String mInterfaceName;
-    private boolean mRegisteredForPreDhcpNotification = false;
-
-    private static final int BASE = Protocol.BASE_DHCP;
-
-    /* Commands from controller to start/stop DHCP */
-    public static final int CMD_START_DHCP                  = BASE + 1;
-    public static final int CMD_STOP_DHCP                   = BASE + 2;
-    public static final int CMD_RENEW_DHCP                  = BASE + 3;
-
-    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
-    public static final int CMD_PRE_DHCP_ACTION             = BASE + 4;
-    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
-     * success/failure */
-    public static final int CMD_POST_DHCP_ACTION            = BASE + 5;
-    /* Notification from DHCP state machine before quitting */
-    public static final int CMD_ON_QUIT                     = BASE + 6;
-
-    /* Command from controller to indicate DHCP discovery/renewal can continue
-     * after pre DHCP action is complete */
-    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = BASE + 7;
-
-    /* Command from ourselves to see if DHCP results are available */
-    private static final int CMD_GET_DHCP_RESULTS           = BASE + 8;
-
-    /* Message.arg1 arguments to CMD_POST_DHCP notification */
-    public static final int DHCP_SUCCESS = 1;
-    public static final int DHCP_FAILURE = 2;
-
-    private State mDefaultState = new DefaultState();
-    private State mStoppedState = new StoppedState();
-    private State mWaitBeforeStartState = new WaitBeforeStartState();
-    private State mRunningState = new RunningState();
-    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
-    private State mPollingState = new PollingState();
-
-    private DhcpStateMachine(Context context, StateMachine controller, String intf) {
-        super(TAG);
-
-        mContext = context;
-        mController = controller;
-        mInterfaceName = intf;
-
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
-        mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
-
-        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
-        mDhcpRenewWakeLock.setReferenceCounted(false);
-
-        mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                //DHCP renew
-                if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
-                //Lock released after 40s in worst case scenario
-                mDhcpRenewWakeLock.acquire(40000);
-                sendMessage(CMD_RENEW_DHCP);
-            }
-        };
-        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
-
-        addState(mDefaultState);
-            addState(mStoppedState, mDefaultState);
-            addState(mWaitBeforeStartState, mDefaultState);
-            addState(mPollingState, mDefaultState);
-            addState(mRunningState, mDefaultState);
-            addState(mWaitBeforeRenewalState, mDefaultState);
-
-        setInitialState(mStoppedState);
-    }
-
-    public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
-            String intf) {
-        DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
-        dsm.start();
-        return dsm;
-    }
-
-    /**
-     * This sends a notification right before DHCP request/renewal so that the
-     * controller can do certain actions before DHCP packets are sent out.
-     * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
-     * to indicate DHCP can continue
-     *
-     * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
-     * handling during Dhcp
-     */
-    @Override
-    public void registerForPreDhcpNotification() {
-        mRegisteredForPreDhcpNotification = true;
-    }
-
-    /**
-     * Quit the DhcpStateMachine.
-     *
-     * @hide
-     */
-    @Override
-    public void doQuit() {
-        quit();
-    }
-
-    protected void onQuitting() {
-        mController.sendMessage(CMD_ON_QUIT);
-    }
-
-    class DefaultState extends State {
-        @Override
-        public void exit() {
-            mContext.unregisterReceiver(mBroadcastReceiver);
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_RENEW_DHCP:
-                    Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
-                    mDhcpRenewWakeLock.release();
-                    break;
-                default:
-                    Log.e(TAG, "Error! unhandled message  " + message);
-                    break;
-            }
-            return HANDLED;
-        }
-    }
-
-
-    class StoppedState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-                Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
-            }
-            mDhcpResults = null;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_START_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        /* Notify controller before starting DHCP */
-                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
-                        transitionTo(mWaitBeforeStartState);
-                    } else {
-                        if (runDhcpStart()) {
-                            transitionTo(mRunningState);
-                        }
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-    }
-
-    class WaitBeforeStartState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcpStart()) {
-                        transitionTo(mRunningState);
-                    } else {
-                        transitionTo(mPollingState);
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-    }
-
-    class PollingState extends State {
-        private static final long MAX_DELAY_SECONDS = 32;
-        private long delaySeconds;
-
-        private void scheduleNextResultsCheck() {
-            sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000);
-            delaySeconds *= 2;
-            if (delaySeconds > MAX_DELAY_SECONDS) {
-                delaySeconds = MAX_DELAY_SECONDS;
-            }
-        }
-
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, "Entering " + getName() + "\n");
-            delaySeconds = 1;
-            scheduleNextResultsCheck();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_GET_DHCP_RESULTS:
-                    if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName);
-                    if (dhcpSucceeded()) {
-                        transitionTo(mRunningState);
-                    } else {
-                        scheduleNextResultsCheck();
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-
-        @Override
-        public void exit() {
-            if (DBG) Log.d(TAG, "Exiting " + getName() + "\n");
-            removeMessages(CMD_GET_DHCP_RESULTS);
-        }
-    }
-
-    class RunningState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    mAlarmManager.cancel(mDhcpRenewalIntent);
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_RENEW_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        /* Notify controller before starting DHCP */
-                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
-                        transitionTo(mWaitBeforeRenewalState);
-                        //mDhcpRenewWakeLock is released in WaitBeforeRenewalState
-                    } else {
-                        if (!runDhcpRenew()) {
-                            transitionTo(mStoppedState);
-                        }
-                        mDhcpRenewWakeLock.release();
-                    }
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-            }
-            return retValue;
-        }
-    }
-
-    class WaitBeforeRenewalState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    mAlarmManager.cancel(mDhcpRenewalIntent);
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcpRenew()) {
-                       transitionTo(mRunningState);
-                    } else {
-                       transitionTo(mStoppedState);
-                    }
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-        @Override
-        public void exit() {
-            mDhcpRenewWakeLock.release();
-        }
-    }
-
-    private boolean dhcpSucceeded() {
-        DhcpResults dhcpResults = new DhcpResults();
-        if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) {
-            return false;
-        }
-
-        if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName);
-        long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
-
-        //Sanity check for renewal
-        if (leaseDuration >= 0) {
-            //TODO: would be good to notify the user that his network configuration is
-            //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
-            if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
-                leaseDuration = MIN_RENEWAL_TIME_SECS;
-            }
-            //Do it a bit earlier than half the lease duration time
-            //to beat the native DHCP client and avoid extra packets
-            //48% for one hour lease time = 29 minutes
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() +
-                    leaseDuration * 480, //in milliseconds
-                    mDhcpRenewalIntent);
-        } else {
-            //infinite lease time, no renewal needed
-        }
-
-        // Fill in any missing fields in dhcpResults from the previous results.
-        // If mDhcpResults is null (i.e. this is the first server response),
-        // this is a noop.
-        dhcpResults.updateFromDhcpRequest(mDhcpResults);
-        mDhcpResults = dhcpResults;
-        mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
-            .sendToTarget();
-        return true;
-    }
-
-    private boolean runDhcpStart() {
-        /* Stop any existing DHCP daemon before starting new */
-        NetworkUtils.stopDhcp(mInterfaceName);
-        mDhcpResults = null;
-
-        if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
-        if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) {
-            Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " +
-                    NetworkUtils.getDhcpError());
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
-                    .sendToTarget();
-            return false;
-        }
-        return true;
-    }
-
-    private boolean runDhcpRenew() {
-        if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
-        if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) {
-            Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " +
-                    NetworkUtils.getDhcpError());
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
-                    .sendToTarget();
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 5ab2b00..9632ff7 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1218,6 +1218,8 @@
      * Input: Nothing.
      * <p>
      * Output: Nothing.
+     *
+     * @hide
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index e01f2a0..eb3d031 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -72,6 +72,7 @@
     public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503;
     public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504;
     public static final int KM_TAG_AUTH_TIMEOUT = KM_UINT | 505;
+    public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
 
     public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
     public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java
index a4cb703..7017ff5 100644
--- a/core/java/android/view/RenderNode.java
+++ b/core/java/android/view/RenderNode.java
@@ -775,10 +775,6 @@
         mOwningView.mAttachInfo.mViewRootImpl.registerAnimatingRenderNode(this);
     }
 
-    public boolean isAttached() {
-        return mOwningView != null && mOwningView.mAttachInfo != null;
-    }
-
     public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) {
         if (mOwningView == null || mOwningView.mAttachInfo == null) {
             throw new IllegalStateException("Cannot start this animator on a detached view!");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9e9ad67..70a0e01 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -21584,7 +21584,7 @@
      */
     public void setPointerIcon(PointerIcon pointerIcon) {
         mPointerIcon = pointerIcon;
-        if (mAttachInfo == null) {
+        if (mAttachInfo == null || mAttachInfo.mHandlingPointerEvent) {
             return;
         }
         try {
@@ -22637,6 +22637,11 @@
         boolean mHighContrastText;
 
         /**
+         * Set to true if a pointer event is currently being handled.
+         */
+        boolean mHandlingPointerEvent;
+
+        /**
          * Global to the view hierarchy used as a temporary for dealing with
          * x/y points in the transparent region computations.
          */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 6dc5ccc..0517788 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4311,6 +4311,24 @@
         private int processPointerEvent(QueuedInputEvent q) {
             final MotionEvent event = (MotionEvent)q.mEvent;
 
+            mAttachInfo.mUnbufferedDispatchRequested = false;
+            final View eventTarget =
+                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
+                            mCapturingView : mView;
+            mAttachInfo.mHandlingPointerEvent = true;
+            boolean handled = eventTarget.dispatchPointerEvent(event);
+            maybeUpdatePointerIcon(event);
+            mAttachInfo.mHandlingPointerEvent = false;
+            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
+                mUnbufferedInputDispatch = true;
+                if (mConsumeBatchedInputScheduled) {
+                    scheduleConsumeBatchedInputImmediately();
+                }
+            }
+            return handled ? FINISH_HANDLED : FORWARD;
+        }
+
+        private void maybeUpdatePointerIcon(MotionEvent event) {
             if (event.getPointerCount() == 1
                     && event.isFromSource(InputDevice.SOURCE_MOUSE)) {
                 if (event.getActionMasked() == MotionEvent.ACTION_HOVER_ENTER
@@ -4327,19 +4345,6 @@
                     }
                 }
             }
-
-            mAttachInfo.mUnbufferedDispatchRequested = false;
-            final View eventTarget =
-                    (event.isFromSource(InputDevice.SOURCE_MOUSE) && mCapturingView != null) ?
-                            mCapturingView : mView;
-            boolean handled = eventTarget.dispatchPointerEvent(event);
-            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
-                mUnbufferedInputDispatch = true;
-                if (mConsumeBatchedInputScheduled) {
-                    scheduleConsumeBatchedInputImmediately();
-                }
-            }
-            return handled ? FINISH_HANDLED : FORWARD;
         }
 
         private int processTrackballEvent(QueuedInputEvent q) {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 4c63941..62e149a 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -985,7 +985,7 @@
             }
         }
 
-        public List<InputMethodInfo> getEnabledInputMethodListLocked() {
+        public ArrayList<InputMethodInfo> getEnabledInputMethodListLocked() {
             return createEnabledInputMethodListLocked(
                     getEnabledInputMethodsAndSubtypeListLocked());
         }
@@ -1092,7 +1092,7 @@
             return isRemoved;
         }
 
-        private List<InputMethodInfo> createEnabledInputMethodListLocked(
+        private ArrayList<InputMethodInfo> createEnabledInputMethodListLocked(
                 List<Pair<String, ArrayList<String>>> imsList) {
             final ArrayList<InputMethodInfo> res = new ArrayList<>();
             for (Pair<String, ArrayList<String>> ims: imsList) {
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index a106f48..5992f7a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -64,5 +64,6 @@
     public static final int BASE_NETWORK_AGENT                                      = 0x00081000;
     public static final int BASE_NETWORK_MONITOR                                    = 0x00082000;
     public static final int BASE_NETWORK_FACTORY                                    = 0x00083000;
+    public static final int BASE_ETHERNET                                           = 0x00084000;
     //TODO: define all used protocols
 }
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index 14badb7..7a3c598 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -43,13 +43,12 @@
     return env;
 }
 
-static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) {
+static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) {
     class AnimationListenerBridge : public AnimationListener {
     public:
-        AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) {
+        AnimationListenerBridge(JNIEnv* env, jobject finishListener) {
             mFinishListener = env->NewGlobalRef(finishListener);
             env->GetJavaVM(&mJvm);
-            mId = id;
         }
 
         virtual ~AnimationListenerBridge() {
@@ -64,7 +63,7 @@
             env->CallStaticVoidMethod(
                     gVectorDrawableAnimatorClassInfo.clazz,
                     gVectorDrawableAnimatorClassInfo.callOnFinished,
-                    mFinishListener, mId);
+                    mFinishListener);
             releaseJavaObject();
         }
 
@@ -77,9 +76,8 @@
 
         JavaVM* mJvm;
         jobject mFinishListener;
-        jint mId;
     };
-    return new AnimationListenerBridge(env, finishListener, id);
+    return new AnimationListenerBridge(env, finishListener);
 }
 
 static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr,
@@ -144,16 +142,15 @@
     holder->setPropertyDataSource(propertyData, length);
     env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
 }
-static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
+static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
     PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
-    AnimationListener* listener = createAnimationListener(env, finishListener, id);
+    // TODO: keep a ref count in finish listener
+    AnimationListener* listener = createAnimationListener(env, finishListener);
     set->start(listener);
 }
 
-static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
-    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
-    AnimationListener* listener = createAnimationListener(env, finishListener, id);
-    set->reverse(listener);
+static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
+    // TODO: implement reverse
 }
 
 static void end(JNIEnv*, jobject, jlong animatorSetPtr) {
@@ -175,8 +172,8 @@
     {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
     {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
     {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData},
-    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start},
-    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse},
+    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)start},
+    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse},
     {"nEnd", "!(J)V", (void*)end},
     {"nReset", "!(J)V", (void*)reset},
 };
@@ -189,7 +186,7 @@
 
     gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
             env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
-            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V");
+            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V");
     return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
             gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index c9eac79..0926e9b 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -184,7 +184,7 @@
 
 static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
     BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
-    animator->cancel();
+    animator->end();
 }
 
 // ----------------------------------------------------------------------------
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 7699da7..9b989b9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -237,12 +237,21 @@
 
     <protected-broadcast android:name="android.net.nsd.STATE_CHANGED" />
 
-    <protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
+    <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
+    <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+    <protected-broadcast android:name="com.android.nfc.action.LLCP_UP" />
+    <protected-broadcast android:name="com.android.nfc.action.LLCP_DOWN" />
+    <protected-broadcast android:name="com.android.nfc.cardemulation.action.CLOSE_TAP_DIALOG" />
+    <protected-broadcast android:name="com.android.nfc.handover.action.ALLOW_CONNECT" />
+    <protected-broadcast android:name="com.android.nfc.handover.action.DENY_CONNECT" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
     <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
-
-    <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+    <!-- For NFC to BT handover -->
+    <protected-broadcast android:name="android.btopp.intent.action.WHITELIST_DEVICE" />
+    <protected-broadcast android:name="android.btopp.intent.action.STOP_HANDOVER_TRANSFER" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND" />
+    <protected-broadcast android:name="android.nfc.handover.intent.action.HANDOVER_SEND_MULTIPLE" />
 
     <protected-broadcast android:name="android.intent.action.CLEAR_DNS_CACHE" />
     <protected-broadcast android:name="android.intent.action.PROXY_CHANGE" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 68afaba..1f0e96d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2922,9 +2922,9 @@
     <!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
     <string name="share_remote_bugreport_notification_title">Share bug report?</string>
     <!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
-    <string name="sharing_remote_bugreport_notification_title">Sharing bug report</string>
+    <string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
     <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
-    <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared. This may temporarily slow down your device.</string>
+    <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
     <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
     <string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
     <!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 77748a8..af8ccf5 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -238,6 +238,9 @@
             mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
         }
         mAnimatedVectorState.mVectorDrawable.draw(canvas);
+        if (isStarted()) {
+            invalidateSelf();
+        }
     }
 
     @Override
@@ -608,6 +611,10 @@
         return mAnimatorSet.isRunning();
     }
 
+    private boolean isStarted() {
+        return mAnimatorSet.isStarted();
+    }
+
     /**
      * Resets the AnimatedVectorDrawable to the start state as specified in the animators.
      */
@@ -619,6 +626,12 @@
     @Override
     public void start() {
         ensureAnimatorSet();
+
+        // If any one of the animator has not ended, do nothing.
+        if (isStarted()) {
+            return;
+        }
+
         mAnimatorSet.start();
         invalidateSelf();
     }
@@ -639,7 +652,6 @@
     @Override
     public void stop() {
         mAnimatorSet.end();
-        invalidateSelf();
     }
 
     /**
@@ -762,9 +774,6 @@
      * @hide
      */
     public static class VectorDrawableAnimator {
-        private static final int NONE = 0;
-        private static final int START_ANIMATION = 1;
-        private static final int REVERSE_ANIMATION = 2;
         private AnimatorListener mListener = null;
         private final LongArray mStartDelays = new LongArray();
         private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -773,14 +782,15 @@
         private boolean mContainsSequentialAnimators = false;
         private boolean mStarted = false;
         private boolean mInitialized = false;
+        private boolean mAnimationPending = false;
         private boolean mIsReversible = 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> mTarget = null;
         private WeakReference<RenderNode> mLastSeenTarget = null;
-        private int mLastListenerId = 0;
-        private int mPendingAnimationAction = NONE;
+
 
         VectorDrawableAnimator() {
             mSetPtr = nCreateAnimatorSet();
@@ -800,7 +810,6 @@
             mInitialized = true;
 
             // Check reversible.
-            mIsReversible = true;
             if (mContainsSequentialAnimators) {
                 mIsReversible = false;
             } else {
@@ -812,6 +821,7 @@
                     }
                 }
             }
+            mIsReversible = true;
         }
 
         private void parseAnimatorSet(AnimatorSet set, long startTime) {
@@ -1032,28 +1042,36 @@
          * to the last seen RenderNode target and start right away.
          */
         protected void recordLastSeenTarget(DisplayListCanvas canvas) {
-            mLastSeenTarget = new WeakReference<RenderNode>(
-                    RenderNodeAnimatorSetHelper.getTarget(canvas));
-            if (mPendingAnimationAction != NONE) {
+            if (mAnimationPending) {
+                mLastSeenTarget = new WeakReference<RenderNode>(
+                        RenderNodeAnimatorSetHelper.getTarget(canvas));
                 if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                     Log.d(LOGTAG, "Target is set in the next frame");
                 }
-                if (mPendingAnimationAction == START_ANIMATION) {
-                    start();
-                } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
-                    reverse();
-                }
-                mPendingAnimationAction = NONE;
+                mAnimationPending = false;
+                start();
+            } else {
+                mLastSeenTarget = new WeakReference<RenderNode>(
+                        RenderNodeAnimatorSetHelper.getTarget(canvas));
             }
+
+        }
+
+        private boolean setTarget(RenderNode node) {
+            if (mTarget != null && mTarget.get() != null) {
+                // TODO: Maybe we want to support target change.
+                throw new IllegalStateException("Target already set!");
+            }
+
+            node.addAnimator(this);
+            mTarget = new WeakReference<RenderNode>(node);
+            return true;
         }
 
         private boolean useLastSeenTarget() {
-            if (mLastSeenTarget != null) {
-                final RenderNode target = mLastSeenTarget.get();
-                if (target != null && target.isAttached()) {
-                    target.addAnimator(this);
-                    return true;
-                }
+            if (mLastSeenTarget != null && mLastSeenTarget.get() != null) {
+                setTarget(mLastSeenTarget.get());
+                return true;
             }
             return false;
         }
@@ -1063,8 +1081,12 @@
                 return;
             }
 
+            if (mStarted) {
+                return;
+            }
+
             if (!useLastSeenTarget()) {
-                mPendingAnimationAction = START_ANIMATION;
+                mAnimationPending = true;
                 return;
             }
 
@@ -1072,45 +1094,38 @@
                 Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
             }
 
-            mStarted = true;
-            nStart(mSetPtr, this, ++mLastListenerId);
+           nStart(mSetPtr, this);
             if (mListener != null) {
                 mListener.onAnimationStart(null);
             }
+            mStarted = true;
         }
 
         public void end() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
+            if (mInitialized && mStarted) {
                 nEnd(mSetPtr);
+                onAnimationEnd();
             }
         }
 
-        public void reset() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
-                nReset(mSetPtr);
+        void reset() {
+            if (!mInitialized) {
+                return;
             }
+            // TODO: Need to implement reset.
+            Log.w(LOGTAG, "Reset is yet to be implemented");
+            nReset(mSetPtr);
         }
 
         // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
         // animators or when the animator set has a start delay
         void reverse() {
-            if (!mIsReversible || !mInitialized) {
+            if (!mIsReversible) {
                 return;
             }
-            if (!useLastSeenTarget()) {
-                mPendingAnimationAction = REVERSE_ANIMATION;
-                return;
-            }
-            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
-            }
-            mStarted = true;
-            nReverse(mSetPtr, this, ++mLastListenerId);
-            if (mListener != null) {
-                mListener.onAnimationStart(null);
-            }
+            // TODO: Need to support reverse (non-public API)
+            Log.w(LOGTAG, "Reverse is yet to be implemented");
+            nReverse(mSetPtr, this);
         }
 
         public long getAnimatorNativePtr() {
@@ -1140,22 +1155,20 @@
             mListener = null;
         }
 
-        private void onAnimationEnd(int listenerId) {
-            if (listenerId != mLastListenerId) {
-                return;
-            }
-            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "on finished called from native");
-            }
+        private void onAnimationEnd() {
             mStarted = false;
             if (mListener != null) {
                 mListener.onAnimationEnd(null);
             }
+            mTarget = null;
         }
 
         // onFinished: should be called from native
-        private static void callOnFinished(VectorDrawableAnimator set, int id) {
-            set.onAnimationEnd(id);
+        private static void callOnFinished(VectorDrawableAnimator set) {
+            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                Log.d(LOGTAG, "on finished called from native");
+            }
+            set.onAnimationEnd();
         }
     }
 
@@ -1175,8 +1188,8 @@
     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 nStart(long animatorSetPtr, VectorDrawableAnimator set, int id);
-    private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id);
+    private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set);
+    private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set);
     private static native void nEnd(long animatorSetPtr);
     private static native void nReset(long animatorSetPtr);
 }
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index e6276a4..1321a83 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -233,7 +233,8 @@
                 // not set up).
                 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
                         spec.isUserAuthenticationRequired(),
-                        spec.getUserAuthenticationValidityDurationSeconds());
+                        spec.getUserAuthenticationValidityDurationSeconds(),
+                        spec.isUserAuthenticationValidWhileOnBody());
             } catch (IllegalStateException | IllegalArgumentException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -271,7 +272,8 @@
         args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
         KeymasterUtils.addUserAuthArgs(args,
                 spec.isUserAuthenticationRequired(),
-                spec.getUserAuthenticationValidityDurationSeconds());
+                spec.getUserAuthenticationValidityDurationSeconds(),
+                spec.isUserAuthenticationValidWhileOnBody());
         KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                 args,
                 mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 3a0ff1c..830402a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,7 +344,8 @@
                 // not set up).
                 KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
                         mSpec.isUserAuthenticationRequired(),
-                        mSpec.getUserAuthenticationValidityDurationSeconds());
+                        mSpec.getUserAuthenticationValidityDurationSeconds(),
+                        mSpec.isUserAuthenticationValidWhileOnBody());
             } catch (IllegalArgumentException | IllegalStateException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -529,7 +530,8 @@
 
         KeymasterUtils.addUserAuthArgs(args,
                 mSpec.isUserAuthenticationRequired(),
-                mSpec.getUserAuthenticationValidityDurationSeconds());
+                mSpec.getUserAuthenticationValidityDurationSeconds(),
+                mSpec.isUserAuthenticationValidWhileOnBody());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
                 mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
index 8d606bf..5f5f2c2 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
@@ -167,6 +167,8 @@
         boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
                 && (keymasterHwEnforcedUserAuthenticators != 0)
                 && (keymasterSwEnforcedUserAuthenticators == 0);
+        boolean userAuthenticationValidWhileOnBody =
+                keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
 
         return new KeyInfo(entryAlias,
                 insideSecureHardware,
@@ -182,7 +184,8 @@
                 blockModes,
                 userAuthenticationRequired,
                 (int) userAuthenticationValidityDurationSeconds,
-                userAuthenticationRequirementEnforcedBySecureHardware);
+                userAuthenticationRequirementEnforcedBySecureHardware,
+                userAuthenticationValidWhileOnBody);
     }
 
     @Override
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index cdcc7a2..d660020 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -498,7 +498,8 @@
                         KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
                 KeymasterUtils.addUserAuthArgs(importArgs,
                         spec.isUserAuthenticationRequired(),
-                        spec.getUserAuthenticationValidityDurationSeconds());
+                        spec.getUserAuthenticationValidityDurationSeconds(),
+                        spec.isUserAuthenticationValidWhileOnBody());
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                         spec.getKeyValidityStart());
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -692,7 +693,8 @@
             args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
             KeymasterUtils.addUserAuthArgs(args,
                     params.isUserAuthenticationRequired(),
-                    params.getUserAuthenticationValidityDurationSeconds());
+                    params.getUserAuthenticationValidityDurationSeconds(),
+                    params.isUserAuthenticationValidWhileOnBody());
             KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                     args,
                     keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index f3fd129..a84e7f34 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -252,6 +252,7 @@
     private final int mUserAuthenticationValidityDurationSeconds;
     private final byte[] mAttestationChallenge;
     private final boolean mUniqueIdIncluded;
+    private final boolean mUserAuthenticationValidWhileOnBody;
 
     /**
      * @hide should be built with Builder
@@ -277,7 +278,8 @@
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
             byte[] attestationChallenge,
-            boolean uniqueIdIncluded) {
+            boolean uniqueIdIncluded,
+            boolean userAuthenticationValidWhileOnBody) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -321,6 +323,7 @@
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
         mAttestationChallenge = Utils.cloneIfNotNull(attestationChallenge);
         mUniqueIdIncluded = uniqueIdIncluded;
+        mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
     }
 
     /**
@@ -587,6 +590,23 @@
     }
 
     /**
+     * Returns {@code true} if the key will remain authorized while the device is on the user's
+     * body, even after the validity duration has expired.  This option has no effect on keys that
+     * don't have an authentication validity duration, and has no effect if the device lacks a
+     * secure on-body sensor.
+     *
+     * <p>Authorization applies only to secret key and private key operations. Public key operations
+     * are not restricted.
+     *
+     * @see #isUserAuthenticationRequired()
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+     */
+    public boolean isUserAuthenticationValidWhileOnBody() {
+        return mUserAuthenticationValidWhileOnBody;
+    }
+
+    /**
      * Builder of {@link KeyGenParameterSpec} instances.
      */
     public final static class Builder {
@@ -612,6 +632,7 @@
         private int mUserAuthenticationValidityDurationSeconds = -1;
         private byte[] mAttestationChallenge = null;
         private boolean mUniqueIdIncluded = false;
+        private boolean mUserAuthenticationValidWhileOnBody;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -1061,6 +1082,34 @@
         }
 
         /**
+         * Sets whether the key is authorized for use after the authentication validity period is
+         * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+         * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+         * device has not been removed from the user's body since the last successful
+         * authentication.
+         *
+         * <p>On devices that do not have a secure on-body sensor, creating a key with this
+         * parameter set to {@code true} will have no effect; the private or secret key will no
+         * longer be authorized for use after the validity period ends, and a fresh authentication
+         * will be required to use it again.
+         *
+         * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+         * the secure hardware, but the sensors themselves may not be difficult to fool.  It is
+         * recommended that this feature be used to increase slightly the security of keys which
+         * would otherwise have to allow unauthenticated access, or have a very long validity
+         * period. Keys that require high assurance of user authorization should not use this
+         * feature and should set a short validity period.
+         *
+         * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+         * key will remain valid after authentication validity duration has expired.
+         */
+        @NonNull
+        public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+            mUserAuthenticationValidWhileOnBody = remainsValid;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1086,7 +1135,8 @@
                     mUserAuthenticationRequired,
                     mUserAuthenticationValidityDurationSeconds,
                     mAttestationChallenge,
-                    mUniqueIdIncluded);
+                    mUniqueIdIncluded,
+                    mUserAuthenticationValidWhileOnBody);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java
index d726880..f77b5ba 100644
--- a/keystore/java/android/security/keystore/KeyInfo.java
+++ b/keystore/java/android/security/keystore/KeyInfo.java
@@ -79,6 +79,7 @@
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
     private final boolean mUserAuthenticationRequirementEnforcedBySecureHardware;
+    private final boolean mUserAuthenticationValidWhileOnBody;
 
     /**
      * @hide
@@ -97,7 +98,8 @@
             @KeyProperties.BlockModeEnum String[] blockModes,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
-            boolean userAuthenticationRequirementEnforcedBySecureHardware) {
+            boolean userAuthenticationRequirementEnforcedBySecureHardware,
+            boolean userAuthenticationValidWhileOnBody) {
         mKeystoreAlias = keystoreKeyAlias;
         mInsideSecureHardware = insideSecureHardware;
         mOrigin = origin;
@@ -116,6 +118,7 @@
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
         mUserAuthenticationRequirementEnforcedBySecureHardware =
                 userAuthenticationRequirementEnforcedBySecureHardware;
+        mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
     }
 
     /**
@@ -277,4 +280,14 @@
     public boolean isUserAuthenticationRequirementEnforcedBySecureHardware() {
         return mUserAuthenticationRequirementEnforcedBySecureHardware;
     }
+
+    /**
+     * Returns {@code true} if this key will remain usable after its specified validity duration
+     * for as long as the device remains on the user's body.  This is possible only for keys with
+     * a specified validity duration.  Always returns {@code false} on devices that lack a secure
+     * on-body sensor.
+     */
+    public boolean isUserAuthenticationValidWhileOnBody() {
+        return mUserAuthenticationValidWhileOnBody;
+    }
 }
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index c984439..4700b68 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -214,6 +214,7 @@
     private final boolean mRandomizedEncryptionRequired;
     private final boolean mUserAuthenticationRequired;
     private final int mUserAuthenticationValidityDurationSeconds;
+    private final boolean mUserAuthenticationValidWhileOnBody;
 
     private KeyProtection(
             Date keyValidityStart,
@@ -226,7 +227,8 @@
             @KeyProperties.BlockModeEnum String[] blockModes,
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds) {
+            int userAuthenticationValidityDurationSeconds,
+            boolean userAuthenticationValidWhileOnBody) {
         mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
         mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
         mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -240,6 +242,7 @@
         mRandomizedEncryptionRequired = randomizedEncryptionRequired;
         mUserAuthenticationRequired = userAuthenticationRequired;
         mUserAuthenticationValidityDurationSeconds = userAuthenticationValidityDurationSeconds;
+        mUserAuthenticationValidWhileOnBody = userAuthenticationValidWhileOnBody;
     }
 
     /**
@@ -392,6 +395,23 @@
     }
 
     /**
+     * Returns {@code true} if the key will remain authorized while the device is on the user's
+     * body, even after the validity duration has expired.  This option has no effect on keys that
+     * don't have an authentication validity duration, and has no effect if the device lacks a
+     * secure on-body sensor.
+     *
+     * <p>Authorization applies only to secret key and private key operations. Public key operations
+     * are not restricted.
+     *
+     * @see #isUserAuthenticationRequired()
+     * @see #getUserAuthenticationValidityDurationSeconds()
+     * @see Builder#setUserAuthenticationValidWhileOnBody(boolean)
+     */
+    public boolean isUserAuthenticationValidWhileOnBody() {
+        return mUserAuthenticationValidWhileOnBody;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -407,6 +427,7 @@
         private boolean mRandomizedEncryptionRequired = true;
         private boolean mUserAuthenticationRequired;
         private int mUserAuthenticationValidityDurationSeconds = -1;
+        private boolean mUserAuthenticationValidWhileOnBody;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -680,6 +701,34 @@
         }
 
         /**
+         * Sets whether the key is authorized for use after the authentication validity period is
+         * expired (see {@link #setUserAuthenticationValidityDurationSeconds} and {@link
+         * #setUserAuthenticationRequired}) if the device has a secure on-body sensor and if the
+         * device has not been removed from the user's body since the last successful
+         * authentication.
+         *
+         * <p>On devices that do not have a secure on-body sensor, creating a key with this
+         * parameter set to {@code true} will have no effect; the private or secret key will no
+         * longer be authorized for use after the validity period ends, and a fresh authentication
+         * will be required to use it again.
+         *
+         * <p>Note that "secure" on-body sensors are required by Android to have a secure path to
+         * the secure hardware, but the sensors themselves may not be difficult to fool.  It is
+         * recommended that this feature be used to increase slightly the security of keys which
+         * would otherwise have to allow unauthenticated access, or have a very long validity
+         * period. Keys that require high assurance of user authorization should not use this
+         * feature and should set a short validity period.
+         *
+         * @param remainsValid if {@code true}, and if the device supports secure on-body detection,
+         * key will remain valid after authentication validity duration has expired.
+         */
+        @NonNull
+        public Builder setUserAuthenticationValidWhileOnBody(boolean remainsValid) {
+            mUserAuthenticationValidWhileOnBody = remainsValid;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@link KeyProtection}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -697,7 +746,8 @@
                     mBlockModes,
                     mRandomizedEncryptionRequired,
                     mUserAuthenticationRequired,
-                    mUserAuthenticationValidityDurationSeconds);
+                    mUserAuthenticationValidityDurationSeconds,
+                    mUserAuthenticationValidWhileOnBody);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index feafbfa..3a008bc 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -96,7 +96,8 @@
      */
     public static void addUserAuthArgs(KeymasterArguments args,
             boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds) {
+            int userAuthenticationValidityDurationSeconds,
+            boolean userAuthenticationValidWhileOnBody) {
         if (!userAuthenticationRequired) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
             return;
@@ -119,6 +120,10 @@
             args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
                     KeymasterArguments.toUint64(fingerprintOnlySid));
             args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
+            if (userAuthenticationValidWhileOnBody) {
+                throw new ProviderException("Key validity extension while device is on-body is not "
+                        + "supported for keys requiring fingerprint authentication");
+            }
         } else {
             // The key is authorized for use for the specified amount of time after the user has
             // authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -133,6 +138,9 @@
                     KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
             args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
                     userAuthenticationValidityDurationSeconds);
+            if (userAuthenticationValidWhileOnBody) {
+                args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
+            }
         }
     }
 
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index 294edb6..7bd2b24 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -33,7 +33,6 @@
 
 BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
         : mTarget(nullptr)
-        , mStagingTarget(nullptr)
         , mFinalValue(finalValue)
         , mDeltaValue(0)
         , mFromValue(0)
@@ -43,8 +42,7 @@
         , mStartTime(0)
         , mDuration(300)
         , mStartDelay(0)
-        , mMayRunAsync(true)
-        , mPlayTime(0) {
+        , mMayRunAsync(true) {
 }
 
 BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -83,129 +81,26 @@
 }
 
 void BaseRenderNodeAnimator::attach(RenderNode* target) {
-    mStagingTarget = target;
+    mTarget = target;
     onAttached();
 }
 
-void BaseRenderNodeAnimator::start() {
-    mStagingPlayState = PlayState::Running;
-    mStagingRequests.push_back(Request::Start);
-    onStagingPlayStateChanged();
-}
-
-void BaseRenderNodeAnimator::cancel() {
-    mStagingPlayState = PlayState::Finished;
-    mStagingRequests.push_back(Request::Cancel);
-    onStagingPlayStateChanged();
-}
-
-void BaseRenderNodeAnimator::reset() {
-    mStagingPlayState = PlayState::Finished;
-    mStagingRequests.push_back(Request::Reset);
-    onStagingPlayStateChanged();
-}
-
-void BaseRenderNodeAnimator::reverse() {
-    mStagingPlayState = PlayState::Reversing;
-    mStagingRequests.push_back(Request::Reverse);
-    onStagingPlayStateChanged();
-}
-
-void BaseRenderNodeAnimator::end() {
-    mStagingPlayState = PlayState::Finished;
-    mStagingRequests.push_back(Request::End);
-    onStagingPlayStateChanged();
-}
-
-void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
-    switch (request) {
-    case Request::Start:
-        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
-                        mPlayTime : 0;
-        mPlayState = PlayState::Running;
-        break;
-    case Request::Reverse:
-        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
-                        mPlayTime : mDuration;
-        mPlayState = PlayState::Reversing;
-        break;
-    case Request::Reset:
-        mPlayTime = 0;
-        mPlayState = PlayState::Finished;
-        break;
-    case Request::Cancel:
-        mPlayState = PlayState::Finished;
-        break;
-    case Request::End:
-        mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
-        mPlayState = PlayState::Finished;
-        break;
-    default:
-        LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
-    };
-}
-
 void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
-    if (mStagingTarget) {
-        RenderNode* oldTarget = mTarget;
-        mTarget = mStagingTarget;
-        mStagingTarget = nullptr;
-        if (oldTarget && oldTarget != mTarget) {
-            oldTarget->onAnimatorTargetChanged(this);
-        }
-    }
-
     if (!mHasStartValue) {
         doSetStartValue(getValue(mTarget));
     }
-
-    if (!mStagingRequests.empty()) {
-        // Keep track of the play state and play time before they are changed when
-        // staging requests are resolved.
-        nsecs_t currentPlayTime = mPlayTime;
-        PlayState prevFramePlayState = mPlayState;
-
-        // Resolve staging requests one by one.
-        for (Request request : mStagingRequests) {
-            resolveStagingRequest(request);
+    if (mStagingPlayState > mPlayState) {
+        if (mStagingPlayState == PlayState::Restarted) {
+            mStagingPlayState = PlayState::Running;
         }
-        mStagingRequests.clear();
-
-        if (mStagingPlayState == PlayState::Finished) {
-            // Set the staging play time and end the animation
-            updatePlayTime(mPlayTime);
+        mPlayState = mStagingPlayState;
+        // Oh boy, we're starting! Man the battle stations!
+        if (mPlayState == PlayState::Running) {
+            transitionToRunning(context);
+        } else if (mPlayState == PlayState::Finished) {
             callOnFinishedListener(context);
-        } else if (mStagingPlayState == PlayState::Running
-                || mStagingPlayState == PlayState::Reversing) {
-            bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
-            if (prevFramePlayState != mStagingPlayState) {
-                transitionToRunning(context);
-            }
-            if (changed) {
-                // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
-                // requested from UI thread). It is achieved by modifying mStartTime, such that
-                // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
-                // case of reversing)
-                nsecs_t currentFrameTime = context.frameTimeMs();
-                if (mPlayState == PlayState::Reversing) {
-                    // Reverse is not supported for animations with a start delay, so here we
-                    // assume no start delay.
-                    mStartTime = currentFrameTime  - (mDuration - mPlayTime);
-                } else {
-                    // Animation should play forward
-                    if (mPlayTime == 0) {
-                        // If the request is to start from the beginning, include start delay.
-                        mStartTime = currentFrameTime + mStartDelay;
-                    } else {
-                        // If the request is to seek to a non-zero play time, then we skip start
-                        // delay.
-                        mStartTime = currentFrameTime - mPlayTime;
-                    }
-                }
-            }
         }
     }
-    onPushStaging();
 }
 
 void BaseRenderNodeAnimator::transitionToRunning(AnimationContext& context) {
@@ -241,37 +136,37 @@
 
     // This should be set before setValue() so animators can query this time when setValue
     // is called.
-    nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
-    bool finished = updatePlayTime(currentPlayTime);
-    if (finished && mPlayState != PlayState::Finished) {
-        mPlayState = PlayState::Finished;
-        callOnFinishedListener(context);
-    }
-    return finished;
-}
+    nsecs_t currentFrameTime = context.frameTimeMs();
+    onPlayTimeChanged(currentFrameTime - mStartTime);
 
-bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
-    mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
-    onPlayTimeChanged(mPlayTime);
     // If BaseRenderNodeAnimator is handling the delay (not typical), then
     // because the staging properties reflect the final value, we always need
     // to call setValue even if the animation isn't yet running or is still
     // being delayed as we need to override the staging value
-    if (playTime < 0) {
+    if (mStartTime > context.frameTimeMs()) {
         setValue(mTarget, mFromValue);
         return false;
     }
 
     float fraction = 1.0f;
-    if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
-        fraction = mPlayTime / (float) mDuration;
+
+    if (mPlayState == PlayState::Running && mDuration > 0) {
+        fraction = (float)(currentFrameTime - mStartTime) / mDuration;
     }
-    fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
+    if (fraction >= 1.0f) {
+        fraction = 1.0f;
+        mPlayState = PlayState::Finished;
+    }
 
     fraction = mInterpolator->interpolate(fraction);
     setValue(mTarget, mFromValue + (mDeltaValue * fraction));
 
-    return playTime >= mDuration;
+    if (mPlayState == PlayState::Finished) {
+        callOnFinishedListener(context);
+        return true;
+    }
+
+    return false;
 }
 
 void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
@@ -320,36 +215,18 @@
 
 void RenderPropertyAnimator::onAttached() {
     if (!mHasStartValue
-            && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
-        setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
+            && mTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+        setStartValue((mTarget->stagingProperties().*mPropertyAccess->getter)());
     }
 }
 
 void RenderPropertyAnimator::onStagingPlayStateChanged() {
     if (mStagingPlayState == PlayState::Running) {
-        if (mStagingTarget) {
-            (mStagingTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
-        } else {
-            // In the case of start delay where stagingTarget has been sync'ed over and null'ed
-            // we delay the properties update to push staging.
-            mShouldUpdateStagingProperties = true;
-        }
+        (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
     } else if (mStagingPlayState == PlayState::Finished) {
         // We're being canceled, so make sure that whatever values the UI thread
         // is observing for us is pushed over
-        mShouldSyncPropertyFields = true;
-    }
-}
-
-void RenderPropertyAnimator::onPushStaging() {
-    if (mShouldUpdateStagingProperties) {
-        (mTarget->mutateStagingProperties().*mPropertyAccess->setter)(finalValue());
-        mShouldUpdateStagingProperties = false;
-    }
-
-    if (mShouldSyncPropertyFields) {
         mTarget->setPropertyFieldsDirty(dirtyMask());
-        mShouldSyncPropertyFields = false;
     }
 }
 
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index fdae0f3..2c9c9c3 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -24,8 +24,6 @@
 
 #include "utils/Macros.h"
 
-#include <vector>
-
 namespace android {
 namespace uirenderer {
 
@@ -61,14 +59,14 @@
         mMayRunAsync = mayRunAsync;
     }
     bool mayRunAsync() { return mMayRunAsync; }
-    ANDROID_API void start();
-    ANDROID_API 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 void start() {
+        if (mStagingPlayState == PlayState::NotStarted) {
+            mStagingPlayState = PlayState::Running;
+        } else {
+            mStagingPlayState = PlayState::Restarted;
+        }
+        onStagingPlayStateChanged(); }
+    ANDROID_API void end() { mStagingPlayState = PlayState::Finished; onStagingPlayStateChanged(); }
 
     void attach(RenderNode* target);
     virtual void onAttached() {}
@@ -76,42 +74,36 @@
     void pushStaging(AnimationContext& context);
     bool animate(AnimationContext& context);
 
-    bool isRunning() { return mPlayState == PlayState::Running
-            || mPlayState == PlayState::Reversing; }
+    bool isRunning() { return mPlayState == PlayState::Running; }
     bool isFinished() { return mPlayState == PlayState::Finished; }
     float finalValue() { return mFinalValue; }
 
     ANDROID_API virtual uint32_t dirtyMask() = 0;
 
     void forceEndNow(AnimationContext& context);
-    RenderNode* target() { return mTarget; }
-    RenderNode* stagingTarget() { return mStagingTarget; }
 
 protected:
     // PlayState is used by mStagingPlayState and mPlayState to track the state initiated from UI
     // thread and Render Thread animation state, respectively.
     // From the UI thread, mStagingPlayState transition looks like
-    // NotStarted -> Running/Reversing -> Finished
-    //                ^                     |
-    //                |                     |
-    //                ----------------------
+    // NotStarted -> Running -> Finished
+    //                ^            |
+    //                |            |
+    //            Restarted <------
     // Note: For mStagingState, the Finished state (optional) is only set when the animation is
     // terminated by user.
     //
     // On Render Thread, mPlayState transition:
-    // NotStart -> Running/Reversing-> Finished
-    //                ^                 |
-    //                |                 |
-    //                ------------------
-    // Note that if the animation is in Running/Reversing state, calling start or reverse again
-    // would do nothing if the animation has the same play direction as the request; otherwise,
-    // the animation would start from where it is and change direction (i.e. Reversing <-> Running)
+    // NotStart -> Running -> Finished
+    //                ^            |
+    //                |            |
+    //                -------------
 
     enum class PlayState {
         NotStarted,
         Running,
-        Reversing,
         Finished,
+        Restarted,
     };
 
     BaseRenderNodeAnimator(float finalValue);
@@ -119,15 +111,14 @@
 
     virtual float getValue(RenderNode* target) const = 0;
     virtual void setValue(RenderNode* target, float value) = 0;
+    RenderNode* target() { return mTarget; }
 
     void callOnFinishedListener(AnimationContext& context);
 
     virtual void onStagingPlayStateChanged() {}
     virtual void onPlayTimeChanged(nsecs_t playTime) {}
-    virtual void onPushStaging() {}
 
     RenderNode* mTarget;
-    RenderNode* mStagingTarget;
 
     float mFinalValue;
     float mDeltaValue;
@@ -141,28 +132,13 @@
     nsecs_t mDuration;
     nsecs_t mStartDelay;
     bool mMayRunAsync;
-    // Play Time tracks the progress of animation, it should always be [0, mDuration], 0 being
-    // the beginning of the animation, will reach mDuration at the end of an animation.
-    nsecs_t mPlayTime;
 
     sp<AnimationListener> mListener;
 
 private:
-    enum class Request {
-        Start,
-        Reverse,
-        Reset,
-        Cancel,
-        End
-    };
     inline void checkMutable();
     virtual void transitionToRunning(AnimationContext& context);
     void doSetStartValue(float value);
-    bool updatePlayTime(nsecs_t playTime);
-    void resolveStagingRequest(Request request);
-
-    std::vector<Request> mStagingRequests;
-
 };
 
 class RenderPropertyAnimator : public BaseRenderNodeAnimator {
@@ -191,7 +167,6 @@
     virtual void setValue(RenderNode* target, float value) override;
     virtual void onAttached() override;
     virtual void onStagingPlayStateChanged() override;
-    virtual void onPushStaging() override;
 
 private:
     typedef bool (RenderProperties::*SetFloatProperty)(float value);
@@ -201,8 +176,6 @@
     const PropertyAccessors* mPropertyAccess;
 
     static const PropertyAccessors PROPERTY_ACCESSOR_LUT[];
-    bool mShouldSyncPropertyFields = false;
-    bool mShouldUpdateStagingProperties = false;
 };
 
 class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 2198fcc..cd30b18 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -27,8 +27,9 @@
 
 using namespace std;
 
-static void detach(sp<BaseRenderNodeAnimator>& animator) {
+static void unref(BaseRenderNodeAnimator* animator) {
     animator->detach();
+    animator->decStrong(nullptr);
 }
 
 AnimatorManager::AnimatorManager(RenderNode& parent)
@@ -37,28 +38,14 @@
 }
 
 AnimatorManager::~AnimatorManager() {
-    for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
-    for_each(mAnimators.begin(), mAnimators.end(), detach);
+    for_each(mNewAnimators.begin(), mNewAnimators.end(), unref);
+    for_each(mAnimators.begin(), mAnimators.end(), unref);
 }
 
 void AnimatorManager::addAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-    RenderNode* stagingTarget = animator->stagingTarget();
-    if (stagingTarget == &mParent) {
-        return;
-    }
-    mNewAnimators.emplace_back(animator.get());
-    // If the animator is already attached to other RenderNode, remove it from that RenderNode's
-    // new animator list. This ensures one animator only ends up in one newAnimatorList during one
-    // frame, even when it's added multiple times to multiple targets.
-    if (stagingTarget) {
-        stagingTarget->removeAnimator(animator);
-    }
+    animator->incStrong(nullptr);
     animator->attach(&mParent);
-}
-
-void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-    mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
-            mNewAnimators.end());
+    mNewAnimators.push_back(animator.get());
 }
 
 void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
@@ -69,40 +56,38 @@
             &mParent, mParent.getName());
 }
 
+template<typename T>
+static void move_all(T& source, T& dest) {
+    dest.reserve(source.size() + dest.size());
+    for (typename T::iterator it = source.begin(); it != source.end(); it++) {
+        dest.push_back(*it);
+    }
+    source.clear();
+}
+
 void AnimatorManager::pushStaging() {
     if (mNewAnimators.size()) {
         LOG_ALWAYS_FATAL_IF(!mAnimationHandle,
                 "Trying to start new animators on %p (%s) without an animation handle!",
                 &mParent, mParent.getName());
-
-        // Only add new animators that are not already in the mAnimators list
-        for (auto& anim : mNewAnimators) {
-            if (anim->target() != &mParent) {
-                mAnimators.push_back(std::move(anim));
-            }
-        }
-        mNewAnimators.clear();
+        // Since this is a straight move, we don't need to inc/dec the ref count
+        move_all(mNewAnimators, mAnimators);
     }
-    for (auto& animator : mAnimators) {
-        animator->pushStaging(mAnimationHandle->context());
+    for (vector<BaseRenderNodeAnimator*>::iterator it = mAnimators.begin(); it != mAnimators.end(); it++) {
+        (*it)->pushStaging(mAnimationHandle->context());
     }
 }
 
-void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
-    LOG_ALWAYS_FATAL_IF(animator->target() == &mParent, "Target has not been changed");
-    mAnimators.erase(std::remove(mAnimators.begin(), mAnimators.end(), animator), mAnimators.end());
-}
-
 class AnimateFunctor {
 public:
     AnimateFunctor(TreeInfo& info, AnimationContext& context)
             : dirtyMask(0), mInfo(info), mContext(context) {}
 
-    bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+    bool operator() (BaseRenderNodeAnimator* animator) {
         dirtyMask |= animator->dirtyMask();
         bool remove = animator->animate(mContext);
         if (remove) {
-            animator->detach();
+            animator->decStrong(nullptr);
         } else {
             if (animator->isRunning()) {
                 mInfo.out.hasAnimations = true;
@@ -144,18 +129,20 @@
 
 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
     AnimateFunctor functor(info, mAnimationHandle->context());
-    auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
+    std::vector< BaseRenderNodeAnimator* >::iterator newEnd;
+    newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
     mAnimationHandle->notifyAnimationsRan();
     mParent.mProperties.updateMatrix();
     return functor.dirtyMask;
 }
 
-static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
-    animator->cancel();
+static void endStagingAnimator(BaseRenderNodeAnimator* animator) {
+    animator->end();
     if (animator->listener()) {
-        animator->listener()->onAnimationFinished(animator.get());
+        animator->listener()->onAnimationFinished(animator);
     }
+    animator->decStrong(nullptr);
 }
 
 void AnimatorManager::endAllStagingAnimators() {
@@ -170,8 +157,9 @@
 public:
     EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
 
-    void operator() (sp<BaseRenderNodeAnimator>& animator) {
+    void operator() (BaseRenderNodeAnimator* animator) {
         animator->forceEndNow(mContext);
+        animator->decStrong(nullptr);
     }
 
 private:
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index 61f6179..fb75eb8 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -39,13 +39,11 @@
     ~AnimatorManager();
 
     void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
-    void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
 
     void setAnimationHandle(AnimationHandle* handle);
     bool hasAnimationHandle() { return mAnimationHandle; }
 
     void pushStaging();
-    void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator);
 
     // Returns the combined dirty mask of all animators run
     uint32_t animate(TreeInfo& info);
@@ -68,8 +66,9 @@
     AnimationHandle* mAnimationHandle;
 
     // To improve the efficiency of resizing & removing from the vector
-    std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
-    std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+    // use manual ref counting instead of sp<>.
+    std::vector<BaseRenderNodeAnimator*> mNewAnimators;
+    std::vector<BaseRenderNodeAnimator*> mAnimators;
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index b29f91f..eca1afcc 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -17,8 +17,6 @@
 #include "PropertyValuesAnimatorSet.h"
 #include "RenderNode.h"
 
-#include <algorithm>
-
 namespace android {
 namespace uirenderer {
 
@@ -55,26 +53,16 @@
 }
 
 void PropertyValuesAnimatorSet::onPlayTimeChanged(nsecs_t playTime) {
-    if (playTime == 0 && mDuration > 0) {
-        // Reset all the animators
-        for (auto it = mAnimators.rbegin(); it != mAnimators.rend(); it++) {
-            // Note that this set may containing animators modifying the same property, so when we
-            // reset the animators, we need to make sure the animators that end the first will
-            // have the final say on what the property value should be.
-            (*it)->setFraction(0);
-        }
-    } else if (playTime >= mDuration) {
-        // Skip all the animators to end
-        for (auto& anim : mAnimators) {
-            anim->setFraction(1);
-        }
-    } else {
-        for (auto& anim : mAnimators) {
-            anim->setCurrentPlayTime(playTime);
-        }
+    for (size_t i = 0; i < mAnimators.size(); i++) {
+        mAnimators[i]->setCurrentPlayTime(playTime);
     }
 }
 
+void PropertyValuesAnimatorSet::reset() {
+    // TODO: implement reset through adding a play state because we need to support reset() even
+    // during an animation run.
+}
+
 void PropertyValuesAnimatorSet::start(AnimationListener* listener) {
     init();
     mOneShotListener = listener;
@@ -82,23 +70,20 @@
 }
 
 void PropertyValuesAnimatorSet::reverse(AnimationListener* listener) {
-    init();
-    mOneShotListener = listener;
-    BaseRenderNodeAnimator::reverse();
+// TODO: implement reverse
 }
 
 void PropertyValuesAnimatorSet::init() {
     if (mInitialized) {
         return;
     }
-
-    // Sort the animators by their total duration. Note that all the animators in the set start at
-    // the same time, so the ones with longer total duration (which includes start delay) will
-    // be the ones that end later.
-    std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
-        return a->getTotalDuration() < b->getTotalDuration();
-    });
-    mDuration = mAnimators[mAnimators.size() - 1]->getTotalDuration();
+    nsecs_t maxDuration = 0;
+    for (size_t i = 0; i < mAnimators.size(); i++) {
+        if (maxDuration < mAnimators[i]->getTotalDuration()) {
+            maxDuration = mAnimators[i]->getTotalDuration();
+        }
+    }
+    mDuration = maxDuration;
     mInitialized = true;
 }
 
@@ -121,19 +106,18 @@
 void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
     if (playTime >= mStartDelay && playTime < mTotalDuration) {
          nsecs_t currentIterationPlayTime = (playTime - mStartDelay) % mDuration;
-         float fraction = currentIterationPlayTime / (float) mDuration;
-         setFraction(fraction);
+         mLatestFraction = currentIterationPlayTime / (float) mDuration;
     } else if (mLatestFraction < 1.0f && playTime >= mTotalDuration) {
-        // This makes sure we only set the fraction = 1 once. It is needed because there might
-        // be another animator modifying the same property after this animator finishes, we need
-        // to make sure we don't set conflicting values on the same property within one frame.
-        setFraction(1.0f);
+        mLatestFraction = 1.0f;
+    } else {
+        return;
     }
+
+    setFraction(mLatestFraction);
 }
 
 void PropertyAnimator::setFraction(float fraction) {
-    mLatestFraction = fraction;
-    float interpolatedFraction = mInterpolator->interpolate(fraction);
+    float interpolatedFraction = mInterpolator->interpolate(mLatestFraction);
     mPropertyValuesHolder->setFraction(interpolatedFraction);
 }
 
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index c7ae7c0..4c7ce52 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -50,6 +50,7 @@
 
     void start(AnimationListener* listener);
     void reverse(AnimationListener* listener);
+    void reset();
 
     void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
             Interpolator* interpolators, int64_t startDelays,
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 9ac76a4..bade216 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -218,10 +218,6 @@
     mAnimatorManager.addAnimator(animator);
 }
 
-void RenderNode::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
-    mAnimatorManager.removeAnimator(animator);
-}
-
 void RenderNode::damageSelf(TreeInfo& info) {
     if (isRenderable()) {
         if (properties().getClipDamageToBounds()) {
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index e037645..f248de54 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -187,12 +187,6 @@
 
     // UI thread only!
     ANDROID_API void addAnimator(const sp<BaseRenderNodeAnimator>& animator);
-    void removeAnimator(const sp<BaseRenderNodeAnimator>& animator);
-
-    // This can only happen during pushStaging()
-    void onAnimatorTargetChanged(BaseRenderNodeAnimator* animator) {
-        mAnimatorManager.onAnimatorTargetChanged(animator);
-    }
 
     AnimatorManager& animators() { return mAnimatorManager; }
 
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
index 6f98509..6f153c1 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
@@ -41,26 +41,6 @@
 
     </FrameLayout>
 
-    <FrameLayout
-        android:id="@+id/lights_out"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <LinearLayout
-            android:id="@+id/ends_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal" />
-
-        <LinearLayout
-            android:id="@+id/center_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:orientation="horizontal" />
-
-    </FrameLayout>
-
     <com.android.systemui.statusbar.policy.DeadZone
         android:id="@+id/deadzone"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index 142d13a..2bf4d9c 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -42,26 +42,6 @@
 
     </FrameLayout>
 
-    <FrameLayout
-        android:id="@+id/lights_out"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <LinearLayout
-            android:id="@+id/ends_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal" />
-
-        <LinearLayout
-            android:id="@+id/center_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:orientation="horizontal" />
-
-    </FrameLayout>
-
     <com.android.systemui.statusbar.policy.DeadZone
         android:id="@+id/deadzone"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 3b7b369..7601efc 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -42,26 +42,6 @@
 
     </FrameLayout>
 
-    <FrameLayout
-        android:id="@+id/lights_out"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <com.android.systemui.statusbar.phone.ReverseLinearLayout
-            android:id="@+id/ends_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="vertical" />
-
-        <com.android.systemui.statusbar.phone.ReverseLinearLayout
-            android:id="@+id/center_group_lightsout"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:orientation="vertical" />
-
-    </FrameLayout>
-
     <com.android.systemui.statusbar.policy.DeadZone
         android:id="@+id/deadzone"
         android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index bed8f1b..858f487 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -50,30 +50,6 @@
             android:layout_height="0dp"
             android:layout_weight="1" />
 
-    <LinearLayout
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:paddingEnd="8dp"
-            android:gravity="end">
+    <include layout="@layout/qs_detail_buttons" />
 
-        <TextView
-                android:id="@android:id/button2"
-                style="@style/QSBorderlessButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginEnd="8dp"
-                android:minWidth="132dp"
-                android:textAppearance="@style/TextAppearance.QS.DetailButton"
-                android:focusable="true" />
-
-        <TextView
-                android:id="@android:id/button1"
-                style="@style/QSBorderlessButton"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:minWidth="88dp"
-                android:textAppearance="@style/TextAppearance.QS.DetailButton"
-                android:focusable="true"/>
-
-    </LinearLayout>
 </com.android.systemui.qs.QSDetail>
diff --git a/packages/SystemUI/res/layout/qs_detail_buttons.xml b/packages/SystemUI/res/layout/qs_detail_buttons.xml
new file mode 100644
index 0000000..03ed62b
--- /dev/null
+++ b/packages/SystemUI/res/layout/qs_detail_buttons.xml
@@ -0,0 +1,42 @@
+<?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.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:paddingEnd="8dp"
+    android:gravity="end">
+
+    <TextView
+        android:id="@android:id/button2"
+        style="@style/QSBorderlessButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_marginEnd="8dp"
+        android:minWidth="132dp"
+        android:textAppearance="@style/TextAppearance.QS.DetailButton"
+        android:focusable="true" />
+
+    <TextView
+        android:id="@android:id/button1"
+        style="@style/QSBorderlessButton"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="88dp"
+        android:textAppearance="@style/TextAppearance.QS.DetailButton"
+        android:focusable="true"/>
+
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
new file mode 100644
index 0000000..efe63d7
--- /dev/null
+++ b/packages/SystemUI/res/layout/tuner_zen_mode_panel.xml
@@ -0,0 +1,48 @@
+<?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.
+-->
+<!-- extends LinearLayout -->
+<com.android.systemui.tuner.TunerZenModePanel
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/tuner_zen_mode_panel"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:clipChildren="false"
+    android:visibility="gone"
+    android:orientation="vertical" >
+
+    <View
+        android:id="@+id/zen_embedded_divider"
+        android:layout_width="match_parent"
+        android:layout_height="1dp"
+        android:layout_marginBottom="12dp"
+        android:layout_marginTop="8dp"
+        android:background="@color/qs_tile_divider" />
+
+    <include
+        android:layout_width="match_parent"
+        android:layout_height="48dp"
+        android:layout_marginStart="16dp"
+        android:id="@+id/tuner_zen_switch"
+        layout="@layout/qs_detail_header" />
+
+    <include layout="@layout/zen_mode_panel" />
+
+    <include
+        android:id="@+id/tuner_zen_buttons"
+        layout="@layout/qs_detail_buttons" />
+
+</com.android.systemui.tuner.TunerZenModePanel>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 34796cd..e4effd4 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -46,7 +46,7 @@
         <include layout="@layout/volume_zen_footer" />
 
         <!-- Only shown from Tuner setting -->
-        <include layout="@layout/zen_mode_panel" />
+        <include layout="@layout/tuner_zen_mode_panel" />
     </LinearLayout>
 
 </RelativeLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fa5b1a9..6135dc6 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -810,12 +810,6 @@
     <!-- Interruption level: Alarms only.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
     <string name="interruption_level_alarms_twoline">Alarms\nonly</string>
 
-    <!-- Interruption level: All interruptions. [CHAR LIMIT=40] -->
-    <string name="interruption_level_all">All</string>
-
-    <!-- Interruption level: All interruptions.  Optimized for narrow two-line display. [CHAR LIMIT=40] -->
-    <string name="interruption_level_all_twoline">All\n</string>
-
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 90d56f7..6029c23 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -758,7 +758,7 @@
                 mPendingLock = false;
             }
         }
-        doKeyguardLaterLockedForChildProfiles();
+        doKeyguardForChildProfilesLocked();
         KeyguardUpdateMonitor.getInstance(mContext).dispatchFinishedGoingToSleep(why);
     }
 
@@ -781,8 +781,7 @@
 
         long timeout;
 
-        if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
-                || policyTimeout <= 0) {
+        if (policyTimeout <= 0) {
             timeout = lockAfterTimeout;
         } else {
             // From DisplaySettings
@@ -815,23 +814,31 @@
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, when, sender);
         if (DEBUG) Log.d(TAG, "setting alarm to turn off keyguard, seq = "
                          + mDelayedShowingSequence);
-        doKeyguardLaterLockedForChildProfiles();
+        doKeyguardLaterForChildProfilesLocked();
     }
 
-    private void doKeyguardLaterLockedForChildProfiles() {
+    private void doKeyguardLaterForChildProfilesLocked() {
         UserManager um = UserManager.get(mContext);
         List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
-        if (profiles.size() > 1) {
-            for (UserInfo info : profiles) {
-                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
-                    long userTimeout = getLockTimeout(info.id);
-                    long userWhen = SystemClock.elapsedRealtime() + userTimeout;
-                    Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
-                    lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
-                    PendingIntent lockSender = PendingIntent.getBroadcast(
-                            mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
-                    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
-                }
+        for (UserInfo info : profiles) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+                long userTimeout = getLockTimeout(info.id);
+                long userWhen = SystemClock.elapsedRealtime() + userTimeout;
+                Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
+                lockIntent.putExtra(Intent.EXTRA_USER_ID, info.id);
+                PendingIntent lockSender = PendingIntent.getBroadcast(
+                        mContext, 0, lockIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+                mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, userWhen, lockSender);
+            }
+        }
+    }
+
+    private void doKeyguardForChildProfilesLocked() {
+        UserManager um = UserManager.get(mContext);
+        List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
+        for (UserInfo info : profiles) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
+                lockProfile(info.id);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
index a58fa86..8a93c5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarController.java
@@ -23,6 +23,7 @@
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.support.v4.util.SimpleArrayMap;
+import android.util.SparseBooleanArray;
 import android.view.View;
 import android.widget.LinearLayout;
 
@@ -71,6 +72,7 @@
 
     private int mCurrentFacetIndex;
     private String mCurrentPackageName;
+    private SparseBooleanArray mFacetHasMultipleAppsCache = new SparseBooleanArray();
 
     public CarNavigationBarController(Context context,
                                       CarNavigationBarView navBar,
@@ -96,6 +98,21 @@
         }
     }
 
+    public void onPackageChange(String packageName) {
+        if (mFacetPackageMap.containsKey(packageName)) {
+            int index = mFacetPackageMap.get(packageName);
+            mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+            // No need to check categories because we've already refreshed the cache.
+            return;
+        }
+
+        String category = getPackageCategory(packageName);
+        if (mFacetCategoryMap.containsKey(category)) {
+            int index = mFacetCategoryMap.get(packageName);
+            mFacetHasMultipleAppsCache.put(index, facetHasMultiplePackages(index));
+        }
+    }
+
     private void bind() {
         // Read up arrays_car.xml and populate the navigation bar here.
         Resources r = mContext.getResources();
@@ -138,6 +155,7 @@
                 initFacetFilterMaps(i,
                         facetPackageNames.getString(i).split(FACET_FILTER_DEMILITER),
                         facetCategories.getString(i).split(FACET_FILTER_DEMILITER));
+                        mFacetHasMultipleAppsCache.put(i, facetHasMultiplePackages(i));
             } catch (URISyntaxException e) {
                 throw new RuntimeException("Malformed intent uri", e);
             }
@@ -229,7 +247,7 @@
 
         if (mNavButtons.get(index) != null) {
             mNavButtons.get(index).setSelected(true /* selected */,
-                    facetHasMultiplePackages(index)  /* showMoreIcon */);
+                    mFacetHasMultipleAppsCache.get(index)  /* showMoreIcon */);
         }
         mCurrentFacetIndex = index;
     }
@@ -268,7 +286,7 @@
 
     private void startActivity(Intent intent) {
         if (mActivityStarter != null && intent != null) {
-            mActivityStarter.startActivity(intent, true);
+            mActivityStarter.startActivity(intent, false);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 08cd053..c32ef0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -18,7 +18,10 @@
 
 import android.app.ActivityManager;
 import android.app.ITaskStackListener;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.graphics.PixelFormat;
 import android.os.Handler;
 import android.os.Looper;
@@ -52,6 +55,7 @@
         mTaskStackListener = new TaskStackListenerImpl(mHandler);
         mSystemServicesProxy = new SystemServicesProxy(mContext);
         mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
+        registerPackageChangeReceivers();
     }
 
     @Override
@@ -81,6 +85,26 @@
         mController = new CarNavigationBarController(context, mCarNavigationBar,
                 this /* ActivityStarter*/);
         mNavigationBarView = mCarNavigationBar;
+
+    }
+
+    private BroadcastReceiver mPackageChangeReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getData() == null || mController == null) {
+                return;
+            }
+            String packageName = intent.getData().getSchemeSpecificPart();
+            mController.onPackageChange(packageName);
+        }
+    };
+
+    private void registerPackageChangeReceivers() {
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        filter.addDataScheme("package");
+        mContext.registerReceiver(mPackageChangeReceiver, filter);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index d625fc2..260c969 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -163,68 +163,29 @@
         String[] start = sets[0].split(BUTTON_SEPARATOR);
         String[] center = sets[1].split(BUTTON_SEPARATOR);
         String[] end = sets[2].split(BUTTON_SEPARATOR);
-        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group),
-                (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
-        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group),
-                (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+        inflateButtons(start, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+        inflateButtons(start, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
 
-        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group),
-                (ViewGroup) mRot0.findViewById(R.id.center_group_lightsout), false);
-        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group),
-                (ViewGroup) mRot90.findViewById(R.id.center_group_lightsout), true);
+        inflateButtons(center, (ViewGroup) mRot0.findViewById(R.id.center_group), false);
+        inflateButtons(center, (ViewGroup) mRot90.findViewById(R.id.center_group), true);
 
         addGravitySpacer((LinearLayout) mRot0.findViewById(R.id.ends_group));
         addGravitySpacer((LinearLayout) mRot90.findViewById(R.id.ends_group));
 
-        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group),
-                (ViewGroup) mRot0.findViewById(R.id.ends_group_lightsout), false);
-        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group),
-                (ViewGroup) mRot90.findViewById(R.id.ends_group_lightsout), true);
+        inflateButtons(end, (ViewGroup) mRot0.findViewById(R.id.ends_group), false);
+        inflateButtons(end, (ViewGroup) mRot90.findViewById(R.id.ends_group), true);
     }
 
     private void addGravitySpacer(LinearLayout layout) {
         layout.addView(new Space(mContext), new LinearLayout.LayoutParams(0, 0, 1));
     }
 
-    private void inflateButtons(String[] buttons, ViewGroup parent, ViewGroup lightsOutParent,
-            boolean landscape) {
+    private void inflateButtons(String[] buttons, ViewGroup parent, boolean landscape) {
         for (int i = 0; i < buttons.length; i++) {
-            copyToLightsout(inflateButton(buttons[i], parent, landscape), lightsOutParent);
+            inflateButton(buttons[i], parent, landscape);
         }
     }
 
-    private void copyToLightsout(View view, ViewGroup lightsOutParent) {
-        if (view == null) return;
-
-        if (view instanceof FrameLayout) {
-            // The only ViewGroup we support in here is a FrameLayout, so copy those manually.
-            FrameLayout original = (FrameLayout) view;
-            FrameLayout layout = new FrameLayout(view.getContext());
-            for (int i = 0; i < original.getChildCount(); i++) {
-                copyToLightsout(original.getChildAt(i), layout);
-            }
-            lightsOutParent.addView(layout, copy(view.getLayoutParams()));
-        } else if (view instanceof Space) {
-            lightsOutParent.addView(new Space(view.getContext()), copy(view.getLayoutParams()));
-        } else {
-            lightsOutParent.addView(generateLightsOutView(view), copy(view.getLayoutParams()));
-        }
-    }
-
-    private View generateLightsOutView(View view) {
-        ImageView imageView = new ImageView(view.getContext());
-        // Copy everything we can about the original view.
-        imageView.setPadding(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),
-                view.getPaddingBottom());
-        imageView.setContentDescription(view.getContentDescription());
-        imageView.setId(view.getId());
-        // Only home gets a big dot, everything else will be little.
-        imageView.setImageResource(view.getId() == R.id.home
-                ? R.drawable.ic_sysbar_lights_out_dot_large
-                : R.drawable.ic_sysbar_lights_out_dot_small);
-        return imageView;
-    }
-
     private ViewGroup.LayoutParams copy(ViewGroup.LayoutParams layoutParams) {
         if (layoutParams instanceof LinearLayout.LayoutParams) {
             return new LinearLayout.LayoutParams(layoutParams.width, layoutParams.height,
@@ -348,9 +309,7 @@
             }
         }
         clearAllChildren((ViewGroup) mRot0.findViewById(R.id.nav_buttons));
-        clearAllChildren((ViewGroup) mRot0.findViewById(R.id.lights_out));
         clearAllChildren((ViewGroup) mRot90.findViewById(R.id.nav_buttons));
-        clearAllChildren((ViewGroup) mRot90.findViewById(R.id.lights_out));
     }
 
     private void clearAllChildren(ViewGroup group) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
index 134c579..1fe0115 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarTransitions.java
@@ -64,42 +64,20 @@
         mLightsOut = lightsOut;
 
         final View navButtons = mView.getCurrentView().findViewById(R.id.nav_buttons);
-        final View lowLights = mView.getCurrentView().findViewById(R.id.lights_out);
 
         // ok, everyone, stop it right there
         navButtons.animate().cancel();
-        lowLights.animate().cancel();
 
-        final float navButtonsAlpha = lightsOut ? 0f : 1f;
-        final float lowLightsAlpha = lightsOut ? 1f : 0f;
+        final float navButtonsAlpha = lightsOut ? 0.5f : 1f;
 
         if (!animate) {
             navButtons.setAlpha(navButtonsAlpha);
-            lowLights.setAlpha(lowLightsAlpha);
-            lowLights.setVisibility(lightsOut ? View.VISIBLE : View.GONE);
         } else {
             final int duration = lightsOut ? LIGHTS_OUT_DURATION : LIGHTS_IN_DURATION;
             navButtons.animate()
                 .alpha(navButtonsAlpha)
                 .setDuration(duration)
                 .start();
-
-            lowLights.setOnTouchListener(mLightsOutListener);
-            if (lowLights.getVisibility() == View.GONE) {
-                lowLights.setAlpha(0f);
-                lowLights.setVisibility(View.VISIBLE);
-            }
-            lowLights.animate()
-                .alpha(lowLightsAlpha)
-                .setDuration(duration)
-                .setInterpolator(new AccelerateInterpolator(2.0f))
-                .setListener(lightsOut ? null : new AnimatorListenerAdapter() {
-                    @Override
-                    public void onAnimationEnd(Animator _a) {
-                        lowLights.setVisibility(View.GONE);
-                    }
-                })
-                .start();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 97d7dd5..6698076 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -79,7 +79,7 @@
     private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
     private Drawable mHomeDefaultIcon, mHomeCarModeIcon;
     private Drawable mRecentIcon;
-    private Drawable mRecentLandIcon;
+    private Drawable mDockedIcon;
 
     private NavigationBarGestureHelper mGestureHelper;
     private DeadZone mDeadZone;
@@ -97,6 +97,7 @@
     private boolean mLayoutTransitionsEnabled = true;
     private boolean mWakeAndUnlocking;
     private boolean mCarMode = false;
+    private boolean mDockedStackExists;
 
     private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
 
@@ -280,7 +281,7 @@
         mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home);
 
         mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent);
-        mRecentLandIcon = mRecentIcon;
+        mDockedIcon = ctx.getDrawable(R.drawable.ic_sysbar_docked);
         getCarModeIcons(ctx);
     }
 
@@ -335,8 +336,7 @@
 
         getBackButton().setImageDrawable(backIcon);
 
-        getRecentsButton().setImageDrawable(
-                mVertical ? mRecentLandIcon : mRecentIcon);
+        updateRecentsIcon();
 
         if (mCarMode) {
             getHomeButton().setImageDrawable(mHomeCarModeIcon);
@@ -507,7 +507,8 @@
                     mHandler.post(new Runnable() {
                         @Override
                         public void run() {
-                            updateRecentsIcon(exists);
+                            mDockedStackExists = exists;
+                            updateRecentsIcon();
                         }
                     });
                 }
@@ -517,10 +518,8 @@
         }
     }
 
-    private void updateRecentsIcon(boolean dockedStackExists) {
-        getRecentsButton().setImageResource(dockedStackExists
-                ? R.drawable.ic_sysbar_docked
-                : R.drawable.ic_sysbar_recent);
+    private void updateRecentsIcon() {
+        getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
     }
 
     public boolean isVertical() {
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
index 5ded885..ad42459 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/NavBarTuner.java
@@ -117,13 +117,9 @@
         if (isRotated) {
             mPreview.findViewById(R.id.rot0).setVisibility(View.GONE);
             final View rot90 = mPreview.findViewById(R.id.rot90);
-            rot90.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
-            rot90.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
         } else {
             mPreview.findViewById(R.id.rot90).setVisibility(View.GONE);
             final View rot0 = mPreview.findViewById(R.id.rot0);
-            rot0.findViewById(R.id.ends_group_lightsout).setVisibility(View.GONE);
-            rot0.findViewById(R.id.center_group_lightsout).setVisibility(View.GONE);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
new file mode 100644
index 0000000..cc0ffb0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerZenModePanel.java
@@ -0,0 +1,141 @@
+/*
+ * 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.tuner;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Checkable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.systemui.Prefs;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.volume.ZenModePanel;
+import com.android.systemui.volume.ZenModePanel.Callback;
+
+public class TunerZenModePanel extends LinearLayout implements OnClickListener {
+    private static final String TAG = "TunerZenModePanel";
+
+    private Callback mCallback;
+    private ZenModePanel mZenModePanel;
+    private View mHeaderSwitch;
+    private int mZenMode;
+    private ZenModeController mController;
+    private View mButtons;
+    private View mMoreSettings;
+    private View mDone;
+    private OnClickListener mDoneListener;
+    private boolean mEditing;
+
+    public TunerZenModePanel(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    public void init(ZenModeController zenModeController) {
+        mController = zenModeController;
+        mHeaderSwitch = findViewById(R.id.tuner_zen_switch);
+        mHeaderSwitch.setVisibility(View.VISIBLE);
+        mHeaderSwitch.setOnClickListener(this);
+        mHeaderSwitch.findViewById(com.android.internal.R.id.up).setVisibility(View.GONE);
+        ((TextView) mHeaderSwitch.findViewById(android.R.id.title)).setText(
+                R.string.quick_settings_dnd_label);
+        mZenModePanel = (ZenModePanel) findViewById(R.id.zen_mode_panel);
+        mZenModePanel.init(zenModeController);
+        mButtons = findViewById(R.id.tuner_zen_buttons);
+        mMoreSettings = mButtons.findViewById(android.R.id.button2);
+        mMoreSettings.setOnClickListener(this);
+        ((TextView) mMoreSettings).setText(R.string.quick_settings_more_settings);
+        mDone = mButtons.findViewById(android.R.id.button1);
+        mDone.setOnClickListener(this);
+        ((TextView) mDone).setText(R.string.quick_settings_done);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mEditing = false;
+    }
+
+    public void setCallback(Callback zenPanelCallback) {
+        mCallback = zenPanelCallback;
+        mZenModePanel.setCallback(zenPanelCallback);
+    }
+
+    @Override
+    public void onClick(View v) {
+        if (v == mHeaderSwitch) {
+            mEditing = true;
+            if (mZenMode == Global.ZEN_MODE_OFF) {
+                mZenMode = Prefs.getInt(mContext, Prefs.Key.DND_FAVORITE_ZEN,
+                        Global.ZEN_MODE_ALARMS);
+                mController.setZen(mZenMode, null, TAG);
+                postUpdatePanel();
+            } else {
+                mZenMode = Global.ZEN_MODE_OFF;
+                mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
+                postUpdatePanel();
+            }
+        } else if (v == mMoreSettings) {
+            Intent intent = new Intent(Settings.ACTION_ZEN_MODE_SETTINGS);
+            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+            getContext().startActivity(intent);
+        } else if (v == mDone) {
+            mEditing = false;
+            setVisibility(View.GONE);
+            mDoneListener.onClick(v);
+        }
+    }
+
+    public boolean isEditing() {
+        return mEditing;
+    }
+
+    public void setZenState(int zenMode) {
+        mZenMode = zenMode;
+        postUpdatePanel();
+    }
+
+    private void postUpdatePanel() {
+        // The complicated structure from reusing the same ZenPanel has resulted in some
+        // unstableness/flickering from callbacks coming in quickly. To solve this just
+        // post the UI updates a little bit.
+        removeCallbacks(mUpdate);
+        postDelayed(mUpdate, 40);
+    }
+
+    public void setDoneListener(OnClickListener onClickListener) {
+        mDoneListener = onClickListener;
+    }
+
+    private void updatePanel() {
+        boolean zenOn = mZenMode != Global.ZEN_MODE_OFF;
+        ((Checkable) mHeaderSwitch.findViewById(android.R.id.toggle)).setChecked(zenOn);
+        mZenModePanel.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+        mButtons.setVisibility(zenOn ? View.VISIBLE : View.GONE);
+    }
+
+    private final Runnable mUpdate = new Runnable() {
+        @Override
+        public void run() {
+            updatePanel();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
index 7b1764f..56a604d 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOverlayActivity.java
@@ -37,7 +37,8 @@
     private View mGuideOverlayView;
     private final Runnable mHideGuideOverlayRunnable = new Runnable() {
         public void run() {
-            mGuideOverlayView.setVisibility(View.INVISIBLE);
+            // TODO: Uncomment this after the b/27224884 is fixed.
+            //mGuideOverlayView.setVisibility(View.INVISIBLE);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 6aae9bd..1810c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -67,6 +67,7 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerZenModePanel;
 import com.android.systemui.volume.VolumeDialogController.State;
 import com.android.systemui.volume.VolumeDialogController.StreamState;
 
@@ -133,7 +134,7 @@
     private int mLastActiveStream;
 
     private boolean mShowFullZen;
-    private final ZenModePanel mZenPanel;
+    private final TunerZenModePanel mZenPanel;
 
     public VolumeDialog(Context context, int windowType, VolumeDialogController controller,
             ZenModeController zenModeController, Callback callback) {
@@ -225,8 +226,7 @@
         mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
         mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
         mZenFooter.init(zenModeController);
-        mZenPanel = (ZenModePanel) mDialog.findViewById(R.id.zen_mode_panel);
-        mZenPanel.addNoneButton();
+        mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
         mZenPanel.init(zenModeController);
         mZenPanel.setCallback(mZenPanelCallback);
 
@@ -671,7 +671,7 @@
         final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
         final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
                 && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
-                && !mShowFullZen;
+                && !mZenPanel.isEditing();
         if (wasVisible != visible && !visible) {
             prepareForCollapse();
         }
@@ -679,12 +679,21 @@
         mZenFooter.update();
 
         final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
-        final boolean fullVisible = mShowFullZen && (mState.zenMode != Global.ZEN_MODE_OFF
-                || mExpanded);
+        final boolean fullVisible = mShowFullZen && !visible;
         if (fullWasVisible != fullVisible && !fullVisible) {
             prepareForCollapse();
         }
         Util.setVisOrGone(mZenPanel, fullVisible);
+        if (fullVisible) {
+            mZenPanel.setZenState(mState.zenMode);
+            mZenPanel.setDoneListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    prepareForCollapse();
+                    mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
+                }
+            });
+        }
     }
 
     private void updateVolumeRowH(VolumeRow row) {
@@ -978,6 +987,7 @@
         private static final int RESCHEDULE_TIMEOUT = 6;
         private static final int STATE_CHANGED = 7;
         private static final int UPDATE_BOTTOM_MARGIN = 8;
+        private static final int UPDATE_FOOTER = 9;
 
         public H() {
             super(Looper.getMainLooper());
@@ -994,6 +1004,7 @@
                 case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
                 case STATE_CHANGED: onStateChangedH(mState); break;
                 case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break;
+                case UPDATE_FOOTER: updateFooterH(); break;
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index 5ca24f7..6976c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -190,12 +190,6 @@
         mZenAlarmWarning = (TextView) findViewById(R.id.zen_alarm_warning);
     }
 
-    public void addNoneButton() {
-        mZenButtons.addButton(R.string.interruption_level_all_twoline,
-                R.string.interruption_level_all,
-                Global.ZEN_MODE_OFF);
-    }
-
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 9e6cd00..3ecff40 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -467,17 +467,18 @@
       if (mCurrentState == STATE_GESTURE_DETECTING) {
           endGestureDetection();
       } else if (mCurrentState == STATE_TOUCH_EXPLORING) {
-          final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
-          final int pointerIdBits = (1 << pointerId);
+          // If the finger is still moving, pass the event on.
+          if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
+              final int pointerId = mReceivedPointerTracker.getPrimaryPointerId();
+              final int pointerIdBits = (1 << pointerId);
 
-          // Cache the event until we discern exploration from gesturing.
-          mSendHoverEnterAndMoveDelayed.addEvent(event);
-
-          // We have just decided that the user is touch,
-          // exploring so start sending events.
-          mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
-          mSendHoverExitDelayed.cancel();
-          sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+              // We have just decided that the user is touch,
+              // exploring so start sending events.
+              mSendHoverEnterAndMoveDelayed.addEvent(event);
+              mSendHoverEnterAndMoveDelayed.forceSendAndRemove();
+              mSendHoverExitDelayed.cancel();
+              sendMotionEvent(event, MotionEvent.ACTION_HOVER_MOVE, pointerIdBits, policyFlags);
+          }
       }
     }
 
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 7770d53..507ac22 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -940,35 +940,18 @@
 
     private void resetDefaultImeLocked(Context context) {
         // Do not reset the default (current) IME when it is a 3rd-party IME
-        if (mCurMethodId != null
-                && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
+        if (mCurMethodId != null && !InputMethodUtils.isSystemIme(mMethodMap.get(mCurMethodId))) {
             return;
         }
-
-        InputMethodInfo defIm = null;
-        for (InputMethodInfo imi : mMethodList) {
-            if (defIm == null && mSystemReady) {
-                final Locale systemLocale = context.getResources().getConfiguration().locale;
-                if (InputMethodUtils.isSystemImeThatHasSubtypeOf(imi, context,
-                        true /* checkDefaultAttribute */, systemLocale, false /* checkCountry */,
-                        InputMethodUtils.SUBTYPE_MODE_ANY)) {
-                    defIm = imi;
-                    Slog.i(TAG, "Selected default: " + imi.getId());
-                }
-            }
+        final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
+                context, mSystemReady, mSettings.getEnabledInputMethodListLocked());
+        if (suitableImes.isEmpty()) {
+            Slog.i(TAG, "No default found");
+            return;
         }
-        if (defIm == null && mMethodList.size() > 0) {
-            defIm = InputMethodUtils.getMostApplicableDefaultIME(
-                    mSettings.getEnabledInputMethodListLocked());
-            if (defIm != null) {
-                Slog.i(TAG, "Default found, using " + defIm.getId());
-            } else {
-                Slog.i(TAG, "No default found");
-            }
-        }
-        if (defIm != null) {
-            setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
-        }
+        final InputMethodInfo defIm = suitableImes.get(0);
+        Slog.i(TAG, "Default found, using " + defIm.getId());
+        setSelectedInputMethodAndSubtypeLocked(defIm, NOT_A_SUBTYPE_ID, false);
     }
 
     private void resetAllInternalStateLocked(final boolean updateOnlyWhenLocaleChanged,
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 12c70a3..2ca5534 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -149,8 +149,9 @@
         }
 
         try {
-            final ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
-                    sbn.getPackageName(), 0);
+            final ApplicationInfo applicationInfo =
+                    mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
+                            0, sbn.getUser().getIdentifier());
             if (applicationInfo.targetSdkVersion < Build.VERSION_CODES.N) {
                 if (isNoisy) {
                     if (importance >= IMPORTANCE_HIGH) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cc5b80e..bf0073a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3340,11 +3340,6 @@
                     + " with flags 0x" + Integer.toHexString(flags), new Throwable());
         }
 
-        // Safe mode means we shouldn't match any third-party components
-        if (mSafeMode) {
-            flags |= PackageManager.MATCH_SYSTEM_ONLY;
-        }
-
         return updateFlags(flags, userId);
     }
 
@@ -3352,6 +3347,11 @@
      * Update given flags when being used to request {@link ResolveInfo}.
      */
     int updateFlagsForResolve(int flags, int userId, Object cookie) {
+        // Safe mode means we shouldn't match any third-party components
+        if (mSafeMode) {
+            flags |= PackageManager.MATCH_SYSTEM_ONLY;
+        }
+
         return updateFlagsForComponent(flags, userId, cookie);
     }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 79d2307..6ec0ba1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5396,6 +5396,9 @@
         }
         synchronized (this) {
             enforceCanSetDeviceOwnerLocked(userId);
+            if (getActiveAdminUncheckedLocked(admin, userId) == null) {
+                throw new IllegalArgumentException("Not active admin: " + admin);
+            }
 
             // Shutting down backup manager service permanently.
             long ident = mInjector.binderClearCallingIdentity();
@@ -5571,6 +5574,11 @@
         }
         synchronized (this) {
             enforceCanSetProfileOwnerLocked(userHandle);
+
+            if (getActiveAdminUncheckedLocked(who, userHandle) == null) {
+                throw new IllegalArgumentException("Not active admin: " + who);
+            }
+
             mOwners.setProfileOwner(who, ownerName, userHandle);
             mOwners.writeProfileOwner(userHandle);
             return true;
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 38551b6..5229b40 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.BaseDhcpStateMachine;
 import android.net.DhcpResults;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
@@ -83,7 +82,7 @@
  *
  * @hide
  */
-public class DhcpClient extends BaseDhcpStateMachine {
+public class DhcpClient extends StateMachine {
 
     private static final String TAG = "DhcpClient";
     private static final boolean DBG = true;
@@ -240,16 +239,10 @@
         mOneshotTimeoutAlarm = makeWakeupMessage("ONESHOT_TIMEOUT", CMD_ONESHOT_TIMEOUT);
     }
 
-    @Override
     public void registerForPreDhcpNotification() {
         mRegisteredForPreDhcpNotification = true;
     }
 
-    public static BaseDhcpStateMachine makeDhcpStateMachine(
-            Context context, StateMachine controller, String intf) {
-        return makeDhcpClient(context, controller, intf);
-    }
-
     public static DhcpClient makeDhcpClient(
             Context context, StateMachine controller, String intf) {
         DhcpClient client = new DhcpClient(context, controller, intf);
@@ -446,12 +439,12 @@
      *
      * @hide
      */
-    @Override
     public void doQuit() {
         Log.d(TAG, "doQuit");
         quit();
     }
 
+    @Override
     protected void onQuitting() {
         Log.d(TAG, "onQuitting");
         mController.sendMessage(CMD_ON_QUIT);
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index b23ad50..6d168b0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1668,7 +1668,12 @@
         // that the test user is not affiliated anymore.
         dpm.clearProfileOwner(admin2);
         final ComponentName admin = new ComponentName("test", "test");
-        markPackageAsInstalled(admin.getPackageName(), null, DpmMockContext.CALLER_USER_HANDLE);
+
+        setUpPackageManagerForFakeAdmin(admin, DpmMockContext.CALLER_UID,
+                /* enabledSetting =*/ PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
+                /* appTargetSdk = */ null, admin2);
+
+        dpm.setActiveAdmin(admin, /* refreshing =*/ true, DpmMockContext.CALLER_USER_HANDLE);
         assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
         assertFalse(dpm.isAffiliatedUser());
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 53ca45d..ca43644 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -19,6 +19,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
@@ -96,12 +97,26 @@
 
     protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
             Integer enabledSetting, Integer appTargetSdk) throws Exception {
+        setUpPackageManagerForFakeAdmin(admin, packageUid, enabledSetting, appTargetSdk,
+                admin);
+    }
+
+    /**
+     * Set up a component in the mock package manager to be an active admin.
+     *
+     * @param admin ComponentName that's visible to the test code, which doesn't have to exist.
+     * @param copyFromAdmin package information for {@code admin} will be built based on this
+     *    component's information.
+     */
+    protected void setUpPackageManagerForFakeAdmin(ComponentName admin, int packageUid,
+            Integer enabledSetting, Integer appTargetSdk, ComponentName copyFromAdmin)
+            throws Exception {
 
         // Set up getApplicationInfo().
 
         final ApplicationInfo ai = DpmTestUtils.cloneParcelable(
                 mRealTestContext.getPackageManager().getApplicationInfo(
-                        admin.getPackageName(),
+                        copyFromAdmin.getPackageName(),
                         PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS));
 
         ai.enabledSetting = enabledSetting == null
@@ -111,6 +126,8 @@
             ai.targetSdkVersion = appTargetSdk;
         }
         ai.uid = packageUid;
+        ai.packageName = admin.getPackageName();
+        ai.name = admin.getClassName();
 
         doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo(
                 eq(admin.getPackageName()),
@@ -120,7 +137,7 @@
         // Set up queryBroadcastReceivers().
 
         final Intent resolveIntent = new Intent();
-        resolveIntent.setComponent(admin);
+        resolveIntent.setComponent(copyFromAdmin);
         final List<ResolveInfo> realResolveInfo =
                 mRealTestContext.getPackageManager().queryBroadcastReceivers(
                         resolveIntent,
@@ -132,7 +149,10 @@
         realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0)));
 
         // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo = ai;
+        final ActivityInfo aci = realResolveInfo.get(0).activityInfo;
+        aci.applicationInfo = ai;
+        aci.packageName = admin.getPackageName();
+        aci.name = admin.getClassName();
 
         doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser(
                 MockUtils.checkIntentComponent(admin),
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index 5e57a25..c2ad9ef 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -16,6 +16,8 @@
 LOCAL_PATH := $(my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
 #
 # Define rules to build temp_layoutlib.jar, which contains a subset of
 # the classes in framework.jar.  The layoutlib_create tool is used to
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index 3dd8002..16e5913 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -18,6 +18,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 LOCAL_JAVA_RESOURCE_DIRS := resources
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
 
 LOCAL_JAVA_LIBRARIES := \
 	layoutlib_api-prebuilt \
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 0e66baa..746ef36 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -73,7 +73,7 @@
     private static final Map<String, FontInfo> sCache =
             new LinkedHashMap<String, FontInfo>(CACHE_SIZE) {
         @Override
-        protected boolean removeEldestEntry(Entry<String, FontInfo> eldest) {
+        protected boolean removeEldestEntry(Map.Entry<String, FontInfo> eldest) {
             return size() > CACHE_SIZE;
         }
 
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
index 8a81d0b..5c062d0 100644
--- a/tools/layoutlib/bridge/tests/Android.mk
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -16,6 +16,8 @@
 
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
 # Only compile source java files in this lib.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_JAVA_RESOURCE_DIRS := res
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index c7f2c41..47377ae 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -16,6 +16,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
 
 LOCAL_JAR_MANIFEST := manifest.txt
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 189ecdc..9e390f6 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -308,6 +308,10 @@
             "java.nio.charset.Charsets",                       "java.nio.charset.StandardCharsets",
             "java.lang.IntegralToString",                      "com.android.tools.layoutlib.java.IntegralToString",
             "java.lang.UnsafeByteSequence",                    "com.android.tools.layoutlib.java.UnsafeByteSequence",
+            // Use android.icu.text versions of DateFormat and SimpleDateFormat since the
+            // original ones do not match the Android implementation
+            "java.text.DateFormat",                            "android.icu.text.DateFormat",
+            "java.text.SimpleDateFormat",                      "android.icu.text.SimpleDateFormat"
         };
 
     private final static String[] EXCLUDED_CLASSES =
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index dafb9c6..c59528e8 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -15,6 +15,8 @@
 LOCAL_PATH := $(call my-dir)
 include $(CLEAR_VARS)
 
+LOCAL_JAVA_LANGUAGE_VERSION := 1.8
+
 # Only compile source java files in this lib.
 LOCAL_SRC_FILES := $(call all-java-files-under, com)