Merge "Switch UM to internal isUserUnlockingOrUnlocked"
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
index 6a49c03..80ce22e 100644
--- a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
@@ -37,4 +37,10 @@
             System.nanoTime();
         }
     }
+
+    @Test
+    public void testBenchmarkOverhead() {
+        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        while (state.keepRunning()) {}
+    }
 }
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
index cdbca63..88cb8e6 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTest.java
@@ -57,8 +57,6 @@
 @LargeTest
 @RunWith(AndroidJUnit4.class)
 public class UserLifecycleTest {
-    private final int MIN_REPEAT_TIMES = 4;
-
     private final int TIMEOUT_REMOVE_USER_MS = 4 * 1000; // 4 sec
     private final int CHECK_USER_REMOVED_INTERVAL_MS = 200; // 0.2 sec
 
@@ -90,7 +88,6 @@
         mAm = context.getSystemService(ActivityManager.class);
         mIam = ActivityManagerNative.getDefault();
         mState = mPerfStatusReporter.getBenchmarkState();
-        mState.setMinRepeatTimes(MIN_REPEAT_TIMES);
         mUsersToRemove = new ArrayList<>();
     }
 
@@ -300,4 +297,4 @@
             mUsersToRemove.add(userId);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
index b27d71b..bf04f6d 100644
--- a/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/BenchmarkState.java
@@ -23,6 +23,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provides a benchmark framework.
@@ -41,39 +42,47 @@
  *     System.out.println(state.summaryLine());
  * }
  */
-public class BenchmarkState {
+public final class BenchmarkState {
     private static final String TAG = "BenchmarkState";
 
-    private static final int NOT_STARTED = 1;  // The benchmark has not started yet.
+    private static final int NOT_STARTED = 0;  // The benchmark has not started yet.
+    private static final int WARMUP = 1; // The benchmark is warming up.
     private static final int RUNNING = 2;  // The benchmark is running.
     private static final int RUNNING_PAUSED = 3;  // The benchmark is temporary paused.
     private static final int FINISHED = 4;  // The benchmark has stopped.
 
     private int mState = NOT_STARTED;  // Current benchmark state.
 
-    private long mNanoPreviousTime = 0;  // Previously captured System.nanoTime().
-    private long mNanoFinishTime = 0;  // Finish if System.nanoTime() returns after than this value.
-    private long mNanoPausedTime = 0; // The System.nanoTime() when the pauseTiming() is called.
-    private long mNanoPausedDuration = 0;  // The duration of paused state in nano sec.
-    private long mNanoTimeLimit = 1 * 1000 * 1000 * 1000;  // 1 sec. Default time limit.
+    private static final long WARMUP_DURATION_NS = ms2ns(250); // warm-up for at least 250ms
+    private static final int WARMUP_MIN_ITERATIONS = 16; // minimum iterations to warm-up for
+
+    // TODO: Tune these values.
+    private static final long TARGET_TEST_DURATION_NS = ms2ns(500); // target testing for 500 ms
+    private static final int MAX_TEST_ITERATIONS = 1000000;
+    private static final int MIN_TEST_ITERATIONS = 100;
+    private static final int REPEAT_COUNT = 5;
+
+    private long mStartTimeNs = 0;  // Previously captured System.nanoTime().
+    private long mPausedTimeNs = 0; // The System.nanoTime() when the pauseTiming() is called.
+    private long mPausedDurationNs = 0;  // The duration of paused state in nano sec.
+
+    private int mIteration = 0;
+    private int mMaxIterations = 0;
+
+    private int mRepeatCount = 0;
 
     // Statistics. These values will be filled when the benchmark has finished.
     // The computation needs double precision, but long int is fine for final reporting.
     private long mMedian = 0;
     private double mMean = 0.0;
     private double mStandardDeviation = 0.0;
-
-    // Number of iterations needed for calculating the stats.
-    private int mMinRepeatTimes = 16;
+    private long mMin = 0;
 
     // Individual duration in nano seconds.
     private ArrayList<Long> mResults = new ArrayList<>();
 
-    /**
-     * Sets the number of iterations needed for calculating the stats. Default is 16.
-     */
-    public void setMinRepeatTimes(int minRepeatTimes) {
-        mMinRepeatTimes = minRepeatTimes;
+    private static final long ms2ns(long ms) {
+        return TimeUnit.MILLISECONDS.toNanos(ms);
     }
 
     /**
@@ -89,8 +98,13 @@
         mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 :
                 mResults.get(size / 2);
 
+        mMin = mResults.get(0);
         for (int i = 0; i < size; ++i) {
-            mMean += mResults.get(i);
+            long result = mResults.get(i);
+            mMean += result;
+            if (result < mMin) {
+                mMin = result;
+            }
         }
         mMean /= (double) size;
 
@@ -108,7 +122,7 @@
             throw new IllegalStateException(
                     "Unable to pause the benchmark. The benchmark has already paused.");
         }
-        mNanoPausedTime = System.nanoTime();
+        mPausedTimeNs = System.nanoTime();
         mState = RUNNING_PAUSED;
     }
 
@@ -119,11 +133,43 @@
             throw new IllegalStateException(
                     "Unable to resume the benchmark. The benchmark is already running.");
         }
-        mNanoPausedDuration += System.nanoTime() - mNanoPausedTime;
-        mNanoPausedTime = 0;
+        mPausedDurationNs += System.nanoTime() - mPausedTimeNs;
+        mPausedTimeNs = 0;
         mState = RUNNING;
     }
 
+    private void beginWarmup() {
+        mStartTimeNs = System.nanoTime();
+        mIteration = 0;
+        mState = WARMUP;
+    }
+
+    private void beginBenchmark(long warmupDuration, int iterations) {
+        mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
+        mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
+                Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
+        mPausedDurationNs = 0;
+        mIteration = 0;
+        mRepeatCount = 0;
+        mState = RUNNING;
+        mStartTimeNs = System.nanoTime();
+    }
+
+    private boolean startNextTestRun() {
+        final long currentTime = System.nanoTime();
+        mResults.add((currentTime - mStartTimeNs - mPausedDurationNs) / mMaxIterations);
+        mRepeatCount++;
+        if (mRepeatCount >= REPEAT_COUNT) {
+            calculateSatistics();
+            mState = FINISHED;
+            return false;
+        }
+        mPausedDurationNs = 0;
+        mIteration = 0;
+        mStartTimeNs = System.nanoTime();
+        return true;
+    }
+
     /**
      * Judges whether the benchmark needs more samples.
      *
@@ -132,23 +178,22 @@
     public boolean keepRunning() {
         switch (mState) {
             case NOT_STARTED:
-                mNanoPreviousTime = System.nanoTime();
-                mNanoFinishTime = mNanoPreviousTime + mNanoTimeLimit;
-                mState = RUNNING;
+                beginWarmup();
+                return true;
+            case WARMUP:
+                mIteration++;
+                // Only check nanoTime on every iteration in WARMUP since we
+                // don't yet have a target iteration count.
+                final long duration = System.nanoTime() - mStartTimeNs;
+                if (mIteration >= WARMUP_MIN_ITERATIONS && duration >= WARMUP_DURATION_NS) {
+                    beginBenchmark(duration, mIteration);
+                }
                 return true;
             case RUNNING:
-                final long currentTime = System.nanoTime();
-                mResults.add(currentTime - mNanoPreviousTime - mNanoPausedDuration);
-                mNanoPausedDuration = 0;
-
-                // To calculate statistics, needs two or more samples.
-                if (mResults.size() > mMinRepeatTimes && currentTime > mNanoFinishTime) {
-                    calculateSatistics();
-                    mState = FINISHED;
-                    return false;
+                mIteration++;
+                if (mIteration >= mMaxIterations) {
+                    return startNextTestRun();
                 }
-
-                mNanoPreviousTime = currentTime;
                 return true;
             case RUNNING_PAUSED:
                 throw new IllegalStateException(
@@ -161,21 +206,28 @@
         }
     }
 
-    public long mean() {
+    private long mean() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
         return (long) mMean;
     }
 
-    public long median() {
+    private long median() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
         return mMedian;
     }
 
-    public long standardDeviation() {
+    private long min() {
+        if (mState != FINISHED) {
+            throw new IllegalStateException("The benchmark hasn't finished");
+        }
+        return mMin;
+    }
+
+    private long standardDeviation() {
         if (mState != FINISHED) {
             throw new IllegalStateException("The benchmark hasn't finished");
         }
@@ -187,10 +239,11 @@
         sb.append("Summary: ");
         sb.append("median=").append(median()).append("ns, ");
         sb.append("mean=").append(mean()).append("ns, ");
+        sb.append("min=").append(min()).append("ns, ");
         sb.append("sigma=").append(standardDeviation()).append(", ");
         sb.append("iteration=").append(mResults.size()).append(", ");
         // print out the first few iterations' number for double checking.
-        int sampleNumber = Math.min(mResults.size(), mMinRepeatTimes);
+        int sampleNumber = Math.min(mResults.size(), 16);
         for (int i = 0; i < sampleNumber; i++) {
             sb.append("No ").append(i).append(" result is ").append(mResults.get(i)).append(", ");
         }
@@ -202,6 +255,7 @@
         Bundle status = new Bundle();
         status.putLong(key + "_median", median());
         status.putLong(key + "_mean", mean());
+        status.putLong(key + "_min", min());
         status.putLong(key + "_standardDeviation", standardDeviation());
         instrumentation.sendStatus(Activity.RESULT_OK, status);
     }
diff --git a/api/current.txt b/api/current.txt
index 9f5a8e2..0508268 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -31683,6 +31683,7 @@
     method public static void notifyDirectoryChange(android.content.ContentResolver);
     field public static final java.lang.String ACCOUNT_NAME = "accountName";
     field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+    field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
     field public static final android.net.Uri CONTENT_URI;
diff --git a/api/system-current.txt b/api/system-current.txt
index 4d7c4af..644bfd2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -34307,6 +34307,7 @@
     method public static void notifyDirectoryChange(android.content.ContentResolver);
     field public static final java.lang.String ACCOUNT_NAME = "accountName";
     field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+    field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
     field public static final android.net.Uri CONTENT_URI;
diff --git a/api/test-current.txt b/api/test-current.txt
index 4be2e7f..1020982 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -31761,6 +31761,7 @@
     method public static void notifyDirectoryChange(android.content.ContentResolver);
     field public static final java.lang.String ACCOUNT_NAME = "accountName";
     field public static final java.lang.String ACCOUNT_TYPE = "accountType";
+    field public static final java.lang.String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_directory";
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/contact_directories";
     field public static final android.net.Uri CONTENT_URI;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 02c8f0c..f487d08 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6586,7 +6586,7 @@
      */
     public void removeUnsafeExtras() {
         if (mExtras != null) {
-            mExtras.filterValues();
+            mExtras = mExtras.filterValues();
         }
     }
 
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 7061589..d04d6c2 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -329,25 +329,49 @@
      * Filter values in Bundle to only basic types.
      * @hide
      */
-    public void filterValues() {
+    public Bundle filterValues() {
         unparcel();
+        Bundle bundle = this;
         if (mMap != null) {
-            for (int i = mMap.size() - 1; i >= 0; i--) {
-                Object value = mMap.valueAt(i);
+            ArrayMap<String, Object> map = mMap;
+            for (int i = map.size() - 1; i >= 0; i--) {
+                Object value = map.valueAt(i);
                 if (PersistableBundle.isValidType(value)) {
                     continue;
                 }
                 if (value instanceof Bundle) {
-                    ((Bundle)value).filterValues();
+                    Bundle newBundle = ((Bundle)value).filterValues();
+                    if (newBundle != value) {
+                        if (map == mMap) {
+                            // The filter had to generate a new bundle, but we have not yet
+                            // created a new one here.  Do that now.
+                            bundle = new Bundle(this);
+                            // Note the ArrayMap<> constructor is guaranteed to generate
+                            // a new object with items in the same order as the original.
+                            map = bundle.mMap;
+                        }
+                        // Replace this current entry with the new child bundle.
+                        map.setValueAt(i, newBundle);
+                    }
+                    continue;
                 }
                 if (value.getClass().getName().startsWith("android.")) {
                     continue;
                 }
-                mMap.removeAt(i);
+                if (map == mMap) {
+                    // This is the first time we have had to remove something, that means we
+                    // need to switch to a new Bundle.
+                    bundle = new Bundle(this);
+                    // Note the ArrayMap<> constructor is guaranteed to generate
+                    // a new object with items in the same order as the original.
+                    map = bundle.mMap;
+                }
+                map.removeAt(i);
             }
         }
         mFlags |= FLAG_HAS_FDS_KNOWN;
         mFlags &= ~FLAG_HAS_FDS;
+        return bundle;
     }
 
     /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a1763c0..8d8c122 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -661,6 +661,12 @@
             ContentValues contentValues = new ContentValues();
             resolver.update(Directory.CONTENT_URI, contentValues, null, null);
         }
+
+        /**
+         * A query parameter that's passed to directory providers which indicates the client
+         * package name that has made the query requests.
+         */
+        public static final String CALLER_PACKAGE_PARAM_KEY = "callerPackage";
     }
 
     /**
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 3e8d577..2316b38 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -436,6 +436,14 @@
     public static final int FLAG_WINDOW_IS_PARTIALLY_OBSCURED = 0x2;
 
     /**
+     * This private flag is only set on {@link #ACTION_HOVER_MOVE} events and indicates that
+     * this event will be immediately followed by a {@link #ACTION_HOVER_EXIT}. It is used to
+     * prevent generating redundant {@link #ACTION_HOVER_ENTER} events.
+     * @hide
+     */
+    public static final int FLAG_HOVER_EXIT_PENDING = 0x4;
+
+    /**
      * Private flag that indicates when the system has detected that this motion event
      * may be inconsistent with respect to the sequence of previously delivered motion events,
      * such as when a pointer move event is sent but the pointer is not down.
@@ -1947,6 +1955,20 @@
                 : flags & ~FLAG_TARGET_ACCESSIBILITY_FOCUS);
     }
 
+    /** @hide */
+    public final boolean isHoverExitPending() {
+        final int flags = getFlags();
+        return (flags & FLAG_HOVER_EXIT_PENDING) != 0;
+    }
+
+    /** @hide */
+    public void setHoverExitPending(boolean hoverExitPending) {
+        final int flags = getFlags();
+        nativeSetFlags(mNativePtr, hoverExitPending
+                ? flags | FLAG_HOVER_EXIT_PENDING
+                : flags & ~FLAG_HOVER_EXIT_PENDING);
+    }
+
     /**
      * Returns the time (in ms) when the user originally pressed down to start
      * a stream of position events.
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49d664e..e37a93a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -48,6 +48,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Insets;
 import android.graphics.Interpolator;
 import android.graphics.LinearGradient;
@@ -763,6 +764,9 @@
         AccessibilityEventSource {
     private static final boolean DBG = false;
 
+    /** @hide */
+    public static boolean DEBUG_DRAW = false;
+
     /**
      * The logging tag used by this class with android.util.Log.
      */
@@ -1190,6 +1194,8 @@
      */
     static final int PARENT_SAVE_DISABLED_MASK = 0x20000000;
 
+    private static Paint sDebugPaint;
+
     /** @hide */
     @IntDef(flag = true,
             value = {
@@ -1661,6 +1667,10 @@
             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
             | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
 
+    static final int DEBUG_CORNERS_COLOR = Color.rgb(63, 127, 255);
+
+    static final int DEBUG_CORNERS_SIZE_DIP = 8;
+
     /**
      * Temporary Rect currently for use in setBackground().  This will probably
      * be extended in the future to hold our own class with more than just
@@ -4749,6 +4759,10 @@
         mRenderNode = RenderNode.create(getClass().getName(), this);
     }
 
+    final boolean debugDraw() {
+        return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
+    }
+
     private static SparseArray<String> getAttributeMap() {
         if (mAttributeMap == null) {
             mAttributeMap = new SparseArray<>();
@@ -16143,6 +16157,9 @@
                         if (mOverlay != null && !mOverlay.isEmpty()) {
                             mOverlay.getOverlayView().draw(canvas);
                         }
+                        if (debugDraw()) {
+                            debugDrawFocus(canvas);
+                        }
                     } else {
                         draw(canvas);
                     }
@@ -17121,6 +17138,41 @@
         return more;
     }
 
+    static Paint getDebugPaint() {
+        if (sDebugPaint == null) {
+            sDebugPaint = new Paint();
+            sDebugPaint.setAntiAlias(false);
+        }
+        return sDebugPaint;
+    }
+
+    final int dipsToPixels(int dips) {
+        float scale = getContext().getResources().getDisplayMetrics().density;
+        return (int) (dips * scale + 0.5f);
+    }
+
+    final private void debugDrawFocus(Canvas canvas) {
+        if (isFocused()) {
+            final int cornerSquareSize = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
+            final int w = getWidth();
+            final int h = getHeight();
+            final Paint paint = getDebugPaint();
+            paint.setColor(DEBUG_CORNERS_COLOR);
+
+            // Draw squares in corners.
+            paint.setStyle(Paint.Style.FILL);
+            canvas.drawRect(0, 0, cornerSquareSize, cornerSquareSize, paint);
+            canvas.drawRect(w - cornerSquareSize, 0, w, cornerSquareSize, paint);
+            canvas.drawRect(0, h - cornerSquareSize, cornerSquareSize, h, paint);
+            canvas.drawRect(w - cornerSquareSize, h - cornerSquareSize, w, h, paint);
+
+            // Draw big X across the view.
+            paint.setStyle(Paint.Style.STROKE);
+            canvas.drawLine(0, 0, getWidth(), getHeight(), paint);
+            canvas.drawLine(0, getHeight(), getWidth(), 0, paint);
+        }
+    }
+
     /**
      * Manually render this view (and all of its children) to the given Canvas.
      * The view must have already done a full layout before this function is
@@ -17175,6 +17227,10 @@
             // Step 6, draw decorations (foreground, scrollbars)
             onDrawForeground(canvas);
 
+            if (debugDraw()) {
+                debugDrawFocus(canvas);
+            }
+
             // we're done...
             return;
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 87a85f1..e39cb96 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -116,8 +116,6 @@
     private static final String TAG = "ViewGroup";
 
     private static final boolean DBG = false;
-    /** @hide */
-    public static boolean DEBUG_DRAW = false;
 
     /**
      * Views which have been hidden or removed which need to be animated on
@@ -476,7 +474,6 @@
     private static final int ARRAY_INITIAL_CAPACITY = 12;
     private static final int ARRAY_CAPACITY_INCREMENT = 12;
 
-    private static Paint sDebugPaint;
     private static float[] sDebugLines;
 
     // Used to draw cached views
@@ -586,10 +583,6 @@
         initFromAttributes(context, attrs, defStyleAttr, defStyleRes);
     }
 
-    private boolean debugDraw() {
-        return DEBUG_DRAW || mAttachInfo != null && mAttachInfo.mDebugLayout;
-    }
-
     private void initViewGroup() {
         // ViewGroup doesn't draw by default
         if (!debugDraw()) {
@@ -1865,8 +1858,11 @@
                 // Synthesize an exit from a move or enter.
                 // Ignore the result because hover focus has moved to a different view.
                 if (action == MotionEvent.ACTION_HOVER_MOVE) {
+                    final boolean hoverExitPending = event.isHoverExitPending();
+                    event.setHoverExitPending(true);
                     dispatchTransformedGenericPointerEvent(
                             event, child); // move
+                    event.setHoverExitPending(hoverExitPending);
                 }
                 eventNoHistory = obtainMotionEventNoHistoryOrSelf(eventNoHistory);
                 eventNoHistory.setAction(MotionEvent.ACTION_HOVER_EXIT);
@@ -1880,8 +1876,10 @@
             firstOldHoverTarget = nextOldHoverTarget;
         }
 
-        // Send events to the view group itself if no children have handled it.
-        boolean newHoveredSelf = !handled;
+        // Send events to the view group itself if no children have handled it and the view group
+        // itself is not currently being hover-exited.
+        boolean newHoveredSelf = !handled &&
+                (action != MotionEvent.ACTION_HOVER_EXIT) && !event.isHoverExitPending();
         if (newHoveredSelf == mHoveredSelf) {
             if (newHoveredSelf) {
                 // Send event to the view group as before.
@@ -3375,11 +3373,6 @@
         fillRect(c, paint, x1, y1, x1 + lw * sign(dx), y1 + dy);
     }
 
-    private int dipsToPixels(int dips) {
-        float scale = getContext().getResources().getDisplayMetrics().density;
-        return (int) (dips * scale + 0.5f);
-    }
-
     private static void drawRectCorners(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint,
             int lineLength, int lineWidth) {
         drawCorner(canvas, paint, x1, y1, lineLength, lineLength, lineWidth);
@@ -3448,10 +3441,10 @@
 
         // Draw clip bounds
         {
-            paint.setColor(Color.rgb(63, 127, 255));
+            paint.setColor(DEBUG_CORNERS_COLOR);
             paint.setStyle(Paint.Style.FILL);
 
-            int lineLength = dipsToPixels(8);
+            int lineLength = dipsToPixels(DEBUG_CORNERS_SIZE_DIP);
             int lineWidth = dipsToPixels(1);
             for (int i = 0; i < getChildCount(); i++) {
                 View c = getChildAt(i);
@@ -7926,14 +7919,6 @@
         }
     }
 
-    private static Paint getDebugPaint() {
-        if (sDebugPaint == null) {
-            sDebugPaint = new Paint();
-            sDebugPaint.setAntiAlias(false);
-        }
-        return sDebugPaint;
-    }
-
     private static void drawRect(Canvas canvas, Paint paint, int x1, int y1, int x2, int y2) {
         if (sDebugLines== null) {
             // TODO: This won't work with multiple UI threads in a single process
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 0942a24..f988130 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3044,7 +3044,7 @@
     <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
         @hide -->
     <permission android:name="android.permission.PEERS_MAC_ADDRESS"
-                android:protectionLevel="signature" />
+                android:protectionLevel="signature|setup" />
 
     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
         can use this permission to ensure incoming Nfc messages are from the Nfc stack
diff --git a/docs/html/wear/preview/downloads.jd b/docs/html/wear/preview/downloads.jd
index da6a06d..bfa384b 100644
--- a/docs/html/wear/preview/downloads.jd
+++ b/docs/html/wear/preview/downloads.jd
@@ -346,7 +346,8 @@
     </p>
 
     <p class="warning">
-      <strong>Warning:</strong> Installing a system image on a watch removes all data from the
+      <strong>Warning:</strong> Installing a system image on a watch
+      removes all data from the
       watch, so you should back up your data first.
     </p>
 
@@ -355,8 +356,7 @@
     </h4>
 
     <p>
-      From the phone, unpair ("Forget") the watch.
-      Then on the watch, enable the Developer Options menu and ADB debugging as
+      On the watch, enable the Developer Options menu and ADB debugging as
       follows:
     </p>
 
@@ -365,14 +365,14 @@
       </li>
 
       <li>Scroll to the bottom of the menu. If no <strong>Developer
-      Options</strong> item is provided, tap <strong>About</strong>.
+      Options</strong> item is provided, tap <strong>System</strong>
+      and then <strong>About</strong>.
       </li>
 
       <li>Tap the build number 7 times.
       </li>
 
-      <li>From the Settings menu, tap the <strong>Developer Options</strong>
-      item.
+      <li>From the Settings menu, tap <strong>Developer Options</strong>.
       </li>
 
       <li>Enable ADB debugging.
@@ -418,7 +418,9 @@
       </li>
 
       <li>Use the following <a href="{@docRoot}tools/help/adb.html">adb
-      command</a> to confirm that the watch is available for flashing:
+      command</a> to confirm that the watch is recognized.
+      You may need to turn ADB debugging off and then on for the watch to
+      be recognized:
       <code>adb devices</code>
       </li>
 
@@ -432,11 +434,11 @@
       devices, <code>fastboot oem unlock</code>
       </li>
 
-      <li>On the watch, select the <strong>Unlock</strong> option.
+      <li>On the watch, select the option to unlock the bootloader.
       </li>
 
-      <li>Navigate to the directory where you unzipped the system image in Step
-      1. At the top level of that directory,
+      <li>On your computer, navigate to the directory where you unzipped the
+      system image in Step 1. At the top level of that directory,
       execute the <code>flash-all</code> script by typing
       <code>flash-all.sh</code> or, in the case of Windows,
       <code>flash-all.bat</code>. The following may need to
@@ -449,16 +451,16 @@
       Set up the watch
     </h4>
 
-      <p>
-        After the <code>flash-all</code> script finishes, your watch reboots.
-        Only pair the watch with a phone (so you can begin testing the preview)
-        by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
-        Additionally, before installing an app, perform the
-        following steps on the watch to re-secure the watch's bootloader:
+    <p>
+      After the <code>flash-all</code> script finishes, the watch reboots.
+      Only pair the watch with a phone (so you can begin testing the preview)
+      by using the instructions in <a href="#set_up_a_phone">Set Up a Phone</a>.
+      Additionally, before installing an app, perform the
+      following steps on the watch to re-secure the watch's bootloader:
     </p>
 
     <ol>
-      <li>Open the Settings menu (on the watch).
+      <li>Open the Settings menu by long-pressing the physical button.
       </li>
 
       <li>Scroll to the bottom of the menu and tap <strong>About</strong>.
@@ -467,15 +469,16 @@
       <li>Tap the build number 7 times.
       </li>
 
-      <li>From the Settings menu, tap the <strong>Developer Options</strong>
-      item.
+      <li>From the Settings menu, tap <strong>Developer Options</strong>.
       </li>
 
       <li>Enable ADB debugging.
       </li>
 
       <li>Connect the watch to your computer and tap <strong>Always allow from
-      this computer</strong>.
+      this computer</strong>. (You may need to turn ADB debugging off
+      and then on, to be prompted to always allow ADB debugging from
+      the connected computer.)
       </li>
 
       <li>Use the following adb command to start the device in fastboot mode:
@@ -487,8 +490,11 @@
       devices, <code>fastboot oem lock</code>
       </li>
 
-      <li>On the watch, continue the boot by choosing
-      <strong>Start</strong> and touching <strong>'0'</strong>.
+      <li>On the watch, continue the boot as follows:
+      On an LGE Watch Urbane 2nd Edition, choose
+      <strong>Start</strong> and touch <strong>'0'</strong>.
+      On a Huawei Watch, confirm that <strong>Reboot</strong> is chosen and
+      long-press the physical button.
       </li>
     </ol>
 
@@ -610,7 +616,8 @@
 
     <p>
       After you install the beta version of the companion app on a phone,
-      you can pair the phone to the watch:
+      unpair ("Forget") any obsolete watch pairings, if necessary.
+      Then you can pair the phone to a newly-imaged watch:
     </p>
 
     <ol>
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 7182da1..d59115e 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -162,6 +162,7 @@
                             r = mRestoredWithoutUids.get(name);
                             if (r == null) {
                                 r = new Record();
+                                r.pkg = name;
                                 mRestoredWithoutUids.put(name, r);
                             }
                         } else {
@@ -606,7 +607,7 @@
     }
 
     public void onPackagesChanged(boolean removingPackage, String[] pkgList) {
-        if (!removingPackage || pkgList == null || pkgList.length == 0
+        if (removingPackage || pkgList == null || pkgList.length == 0
                 || mRestoredWithoutUids.isEmpty()) {
             return; // nothing to do
         }
diff --git a/services/core/java/com/android/server/utils/PriorityDump.java b/services/core/java/com/android/server/utils/PriorityDump.java
new file mode 100644
index 0000000..c05cc3f
--- /dev/null
+++ b/services/core/java/com/android/server/utils/PriorityDump.java
@@ -0,0 +1,179 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
+ * {@link #PRIORITY_ARG} argument.
+ * <p>
+ * Typical usage:
+ *
+ * <pre><code>
+public class SpringfieldNuclearPowerPlant extends Binder {
+
+ private final PriorityDump.PriorityDumper mPriorityDumper = new PriorityDump.PriorityDumper() {
+
+     @Override
+     public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+       pw.println("Donuts in the box: 1");
+     }
+
+     @Override
+     public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+       pw.println("Nuclear reactor status: DANGER - MELTDOWN IMMINENT");
+     }
+  };
+
+  @Override
+  protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+      PriorityDump.dump(mPriorityDumper, fd, pw, args);
+  }
+}
+
+ * </code></pre>
+ *
+ * <strong>Disclaimer</strong>: a real-life service should prioritize core status over donuts :-)
+ *
+ * <p>Then to invoke it:
+ *
+ * <pre><code>
+ *
+    $ adb shell dumpsys snpp
+    Donuts in the box: 1
+    Nuclear reactor status: DANGER - MELTDOWN IMMINENT
+
+    $ adb shell dumpsys snpp --dump_priority CRITICAL
+    Donuts in the box: 1
+
+    $ adb shell dumpsys snpp --dump_priority NORMAL
+    Nuclear reactor status: DANGER - MELTDOWN IMMINENT
+
+ * </code></pre>
+ *
+ *
+ *
+ * <p>To run the unit tests:
+ * <pre><code>
+ *
+ mmm -j32 frameworks/base/services/tests/servicestests/ && \
+ adb install -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk && \
+ adb shell am instrument -e class "com.android.server.utils.PriorityDumpTest" \
+ -w "com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner"
+
+ * </code></pre>
+ *
+ *
+ * @hide
+ */
+public final class PriorityDump {
+
+    public static final String PRIORITY_ARG = "--dump_priority";
+
+    private PriorityDump() {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * Parses {@code} and call the proper {@link PriorityDumper} method when the first argument is
+     * {@code --dump_priority}, stripping the priority and its type.
+     * <p>
+     * For example, if called as {@code --dump_priority HIGH arg1 arg2 arg3}, it will call
+     * <code>dumper.dumpHigh(fd, pw, {"arg1", "arg2", "arg3"}) </code>
+     * <p>
+     * If the {@code --dump_priority} is not set, it calls
+     * {@link PriorityDumper#dump(FileDescriptor, PrintWriter, String[])} passing the whole
+     * {@code args} instead.
+     */
+    public static void dump(PriorityDumper dumper, FileDescriptor fd, PrintWriter pw,
+            String[] args) {
+        if (args != null && args.length >= 2 && args[0].equals(PRIORITY_ARG)) {
+            final String priority = args[1];
+            switch (priority) {
+                case "CRITICAL": {
+                    dumper.dumpCritical(fd, pw, getStrippedArgs(args));
+                    return;
+                }
+                case "HIGH": {
+                    dumper.dumpHigh(fd, pw, getStrippedArgs(args));
+                    return;
+                }
+                case "NORMAL": {
+                    dumper.dumpNormal(fd, pw, getStrippedArgs(args));
+                    return;
+                }
+            }
+        }
+        dumper.dump(fd, pw, args);
+    }
+
+    /**
+     * Gets an array without the {@code --dump_priority PRIORITY} prefix.
+     */
+    private static String[] getStrippedArgs(String[] args) {
+        final String[] stripped = new String[args.length - 2];
+        System.arraycopy(args, 2, stripped, 0, stripped.length);
+        return stripped;
+    }
+
+    /**
+     * Helper for {@link android.os.Binder#dump(java.io.FileDescriptor, String[])} that supports the
+     * {@link #PRIORITY_ARG} argument.
+     *
+     * @hide
+     */
+    public static interface PriorityDumper {
+
+        /**
+         * Dumps only the critical section.
+         */
+        @SuppressWarnings("unused")
+        default void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+        }
+
+        /**
+         * Dumps only the high-priority section.
+         */
+        @SuppressWarnings("unused")
+        default void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
+        }
+
+        /**
+         * Dumps only the normal section.
+         */
+        @SuppressWarnings("unused")
+        default void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+        }
+
+        /**
+         * Dumps all sections.
+         * <p>
+         * This method is called when
+         * {@link PriorityDump#dump(PriorityDumper, FileDescriptor, PrintWriter, String[])} is
+         * called without priority arguments. By default, it calls the 3 {@code dumpTYPE} methods,
+         * so sub-classes just need to implement the priority types they support.
+         */
+        @SuppressWarnings("unused")
+        default void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            dumpCritical(fd, pw, args);
+            dumpHigh(fd, pw, args);
+            dumpNormal(fd, pw, args);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 9b22760..7439f535 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1479,7 +1479,7 @@
         lockWP.cropHint.set(sysWP.cropHint);
         lockWP.width = sysWP.width;
         lockWP.height = sysWP.height;
-        lockWP.allowBackup = false;
+        lockWP.allowBackup = sysWP.allowBackup;
 
         // Migrate the bitmap files outright; no need to copy
         try {
diff --git a/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
new file mode 100644
index 0000000..d378b7c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/utils/PriorityDumpTest.java
@@ -0,0 +1,210 @@
+/**
+ * Copyright (c) 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static com.android.server.utils.PriorityDump.dump;
+
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.same;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import com.android.server.utils.PriorityDump.PriorityDumper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+@SmallTest
+@Presubmit
+@RunWith(JUnit4.class)
+public class PriorityDumpTest {
+
+    private static final String[] EMPTY_ARGS = {};
+
+    @Mock
+    private PriorityDumper mDumper;
+    @Mock
+    private PrintWriter mPw;
+
+    private final FileDescriptor mFd = FileDescriptor.err;
+
+    @Before
+    public void setup() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testNullArgs() {
+        dump(mDumper, mFd, mPw, null);
+        verify(mDumper).dump(same(mFd), same(mPw), eq(null));
+    }
+
+    @Test
+    public void testNoArgs() {
+        dump(mDumper, mFd, mPw, EMPTY_ARGS);
+        verify(mDumper).dump(same(mFd), same(mPw), same(EMPTY_ARGS));
+    }
+
+    @Test
+    public void testNonPriorityArgs() {
+        final String[] args = {
+                "--dumb_priority"
+        };
+        dump(mDumper, mFd, mPw, args);
+        verify(mDumper).dump(same(mFd), same(mPw), same(args));
+    }
+
+    @Test
+    public void testMissingPriority() {
+        final String[] args = {
+                "--dump_priority"
+        };
+        dump(mDumper, mFd, mPw, args);
+        verify(mDumper).dump(same(mFd), same(mPw), same(args));
+    }
+
+    @Test
+    public void testInvalidPriorityNoExtraArgs() {
+        final String[] args = {
+                "--dump_priority", "SUPER_HIGH"
+        };
+        dump(mDumper, mFd, mPw, args);
+        verify(mDumper).dump(same(mFd), same(mPw), same(args));
+    }
+
+    @Test
+    public void testInvalidPriorityExtraArgs() {
+        final String[] args = {
+                "--dump_priority", "SUPER_HIGH", "--high", "--five"
+        };
+        dump(mDumper, mFd, mPw, args);
+        verify(mDumper).dump(same(mFd), same(mPw), same(args));
+    }
+
+    @Test
+    public void testNoPriorityCallsAllMethods() {
+        final String[] args = {
+                "1", "2", "3"
+        };
+
+        // Cannot use mDumper here because it would mock the dump() call.
+        final FakeDumper fakeDumper = new FakeDumper();
+
+        dump(fakeDumper, mFd, mPw, args);
+
+        assertSame(mFd, fakeDumper.criticalFd);
+        assertSame(mPw, fakeDumper.criticalPw);
+        assertSame(args, fakeDumper.criticalArgs);
+        assertSame(mFd, fakeDumper.highFd);
+        assertSame(mPw, fakeDumper.highPw);
+        assertSame(args, fakeDumper.highArgs);
+        assertSame(mFd, fakeDumper.normalFd);
+        assertSame(mPw, fakeDumper.normalPw);
+        assertSame(args, fakeDumper.normalArgs);
+    }
+
+    @Test
+    public void testCriticalNoExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "CRITICAL"
+        });
+        verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(EMPTY_ARGS));
+    }
+
+    @Test
+    public void testCriticalExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "CRITICAL", "--high", "--five"
+        });
+        verify(mDumper).dumpCritical(same(mFd), same(mPw), eq(new String[] {
+                "--high", "--five"
+        }));
+    }
+
+    @Test
+    public void testHighNoExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "HIGH"
+        });
+        verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(EMPTY_ARGS));
+    }
+
+    @Test
+    public void testHighExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "HIGH", "--high", "--five"
+        });
+        verify(mDumper).dumpHigh(same(mFd), same(mPw), eq(new String[] {
+                "--high", "--five"
+        }));
+    }
+
+    @Test
+    public void testNormalNoExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "NORMAL"
+        });
+        verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(EMPTY_ARGS));
+    }
+
+    @Test
+    public void testNormalExtraArgs() {
+        dump(mDumper, mFd, mPw, new String[] {
+                "--dump_priority", "NORMAL", "--high", "--five"
+        });
+        verify(mDumper).dumpNormal(same(mFd), same(mPw), eq(new String[] {
+                "--high", "--five"
+        }));
+    }
+
+    private final class FakeDumper implements PriorityDumper {
+
+        String[] criticalArgs, highArgs, normalArgs;
+        FileDescriptor criticalFd, highFd, normalFd;
+        PrintWriter criticalPw, highPw, normalPw;
+
+        @Override
+        public void dumpCritical(FileDescriptor fd, PrintWriter pw, String[] args) {
+            criticalFd = fd;
+            criticalPw = pw;
+            criticalArgs = args;
+        }
+
+        @Override
+        public void dumpHigh(FileDescriptor fd, PrintWriter pw, String[] args) {
+            highFd = fd;
+            highPw = pw;
+            highArgs = args;
+        }
+
+        @Override
+        public void dumpNormal(FileDescriptor fd, PrintWriter pw, String[] args) {
+            normalFd = fd;
+            normalPw = pw;
+            normalArgs = args;
+        }
+    }
+}