Merge "Fix issue #30601353: Don't warn of non-protected explicit intent broadcasts" into nyc-mr1-dev
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index b58ff1f..d299672 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -147,7 +147,7 @@
             }
 
             final long traceTag = me.mTraceTag;
-            if (traceTag != 0) {
+            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                 Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
             }
             try {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 69f1747..0cdf5e1 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -821,6 +821,17 @@
     static boolean sTextureViewIgnoresDrawableSetters = false;
 
     /**
+     * Prior to N, some ViewGroups would not convert LayoutParams properly even though both extend
+     * MarginLayoutParams. For instance, converting LinearLayout.LayoutParams to
+     * RelativeLayout.LayoutParams would lose margin information. This is fixed on N but target API
+     * check is implemented for backwards compatibility.
+     *
+     * {@hide}
+     */
+    protected static boolean sPreserveMarginParamsInLayoutParamConversion;
+
+
+    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -4052,6 +4063,10 @@
             // On N+, we throw, but that breaks compatibility with apps that use these methods.
             sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
 
+            // Prior to N, we would drop margins in LayoutParam conversions. The fix triggers bugs
+            // in apps so we target check it to avoid breaking existing apps.
+            sPreserveMarginParamsInLayoutParamConversion = targetSdkVersion >= N;
+
             sCompatibilityDone = true;
         }
     }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 029313c..b8c74d8 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -382,13 +382,14 @@
 
     @Override
     protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
-        if (lp instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) lp);
-        } else if (lp instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) lp);
-        } else {
-            return new LayoutParams(lp);
+        if (sPreserveMarginParamsInLayoutParamConversion) {
+            if (lp instanceof LayoutParams) {
+                return new LayoutParams((LayoutParams) lp);
+            } else if (lp instanceof MarginLayoutParams) {
+                return new LayoutParams((MarginLayoutParams) lp);
+            }
         }
+        return new LayoutParams(lp);
     }
 
     @Override
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index 726586e..af2852c 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -868,13 +868,14 @@
 
     @Override
     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
-        if (lp instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) lp);
-        } else if (lp instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) lp);
-        } else {
-            return new LayoutParams(lp);
+        if (sPreserveMarginParamsInLayoutParamConversion) {
+            if (lp instanceof LayoutParams) {
+                return new LayoutParams((LayoutParams) lp);
+            } else if (lp instanceof MarginLayoutParams) {
+                return new LayoutParams((MarginLayoutParams) lp);
+            }
         }
+        return new LayoutParams(lp);
     }
 
     // Draw grid
diff --git a/core/java/android/widget/LinearLayout.java b/core/java/android/widget/LinearLayout.java
index 38d7cd4..f897372 100644
--- a/core/java/android/widget/LinearLayout.java
+++ b/core/java/android/widget/LinearLayout.java
@@ -1844,13 +1844,14 @@
 
     @Override
     protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
-        if (lp instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) lp);
-        } else if (lp instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) lp);
-        } else {
-            return new LayoutParams(lp);
+        if (sPreserveMarginParamsInLayoutParamConversion) {
+            if (lp instanceof LayoutParams) {
+                return new LayoutParams((LayoutParams) lp);
+            } else if (lp instanceof MarginLayoutParams) {
+                return new LayoutParams((MarginLayoutParams) lp);
+            }
         }
+        return new LayoutParams(lp);
     }
 
 
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 0136542..a189d3c 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1104,13 +1104,14 @@
 
     @Override
     protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams lp) {
-        if (lp instanceof LayoutParams) {
-            return new LayoutParams((LayoutParams) lp);
-        } else if (lp instanceof MarginLayoutParams) {
-            return new LayoutParams((MarginLayoutParams) lp);
-        } else {
-            return new LayoutParams(lp);
+        if (sPreserveMarginParamsInLayoutParamConversion) {
+            if (lp instanceof LayoutParams) {
+                return new LayoutParams((LayoutParams) lp);
+            } else if (lp instanceof MarginLayoutParams) {
+                return new LayoutParams((MarginLayoutParams) lp);
+            }
         }
+        return new LayoutParams(lp);
     }
 
     /** @hide */
diff --git a/docs/html/_redirects.yaml b/docs/html/_redirects.yaml
index 00a7edd..fd54b7d 100644
--- a/docs/html/_redirects.yaml
+++ b/docs/html/_redirects.yaml
@@ -819,8 +819,8 @@
   to: /about/versions/marshmallow/android-6.0-changes.html#behavior-apache-http-client
 - from: /shareables/...
   to: https://commondatastorage.googleapis.com/androiddevelopers/shareables/...
-- from: /downloads/
-  to: https://commondatastorage.googleapis.com/androiddevelopers/
+- from: /downloads/...
+  to: https://commondatastorage.googleapis.com/androiddevelopers/...
 - from: /training/performance/battery/network/action-any-traffic.html
   to: /topic/performance/power/network/action-any-traffic.html
 - from: /training/performance/battery/network/action-app-traffic.html
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 6facf20..bdcad79 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -422,7 +422,6 @@
         pushStagingDisplayListChanges(info);
     }
     prepareSubTree(info, childFunctorsNeedLayer, mDisplayList);
-    pushLayerUpdate(info);
 
     if (mDisplayList) {
         for (auto& vectorDrawable : mDisplayList->getVectorDrawables()) {
@@ -433,6 +432,7 @@
             vectorDrawable->setPropertyChangeWillBeConsumed(true);
         }
     }
+    pushLayerUpdate(info);
 
     info.damageAccumulator->popTransform();
 }
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index f04df4b..5a75f40 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -60,6 +60,8 @@
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.res.Configuration;
+import android.graphics.Bitmap;
+import android.hardware.display.DisplayManagerGlobal;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -78,6 +80,8 @@
 import android.util.Log;
 import android.util.Patterns;
 import android.util.SparseArray;
+import android.view.Display;
+import android.view.KeyEvent;
 import android.view.View;
 import android.view.WindowManager;
 import android.view.View.OnFocusChangeListener;
@@ -771,7 +775,6 @@
             }
             msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
-            // TODO: try again using Framework APIs instead of relying on screencap.
             msg = mContext.getString(R.string.bugreport_screenshot_failed);
             Toast.makeText(mContext, msg, Toast.LENGTH_SHORT).show();
         }
@@ -1350,22 +1353,24 @@
     /**
      * Takes a screenshot and save it to the given location.
      */
-    private static boolean takeScreenshot(Context context, String screenshotFile) {
-        final ProcessBuilder screencap = new ProcessBuilder()
-                .command("/system/bin/screencap", "-p", screenshotFile);
-        Log.d(TAG, "Taking screenshot using " + screencap.command());
-        try {
-            final int exitValue = screencap.start().waitFor();
-            if (exitValue == 0) {
+    private static boolean takeScreenshot(Context context, String path) {
+        final Bitmap bitmap = Screenshooter.takeScreenshot();
+        if (bitmap == null) {
+            return false;
+        }
+        boolean status;
+        try (final FileOutputStream fos = new FileOutputStream(path)) {
+            if (bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos)) {
                 ((Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE)).vibrate(150);
                 return true;
+            } else {
+                Log.e(TAG, "Failed to save screenshot on " + path);
             }
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed: " + exitValue);
-        } catch (IOException e) {
-            Log.e(TAG, "screencap (" + screencap.command() + ") failed", e);
-        } catch (InterruptedException e) {
-            Log.w(TAG, "Thread interrupted while screencap still running");
-            Thread.currentThread().interrupt();
+        } catch (IOException e ) {
+            Log.e(TAG, "Failed to save screenshot on " + path, e);
+            return false;
+        } finally {
+            bitmap.recycle();
         }
         return false;
     }
diff --git a/packages/Shell/src/com/android/shell/Screenshooter.java b/packages/Shell/src/com/android/shell/Screenshooter.java
new file mode 100644
index 0000000..3f4895b
--- /dev/null
+++ b/packages/Shell/src/com/android/shell/Screenshooter.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.shell;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Point;
+import android.hardware.display.DisplayManagerGlobal;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Display;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+/**
+ * Helper class used to take screenshots.
+ *
+ * TODO: logic below was copied and pasted from UiAutomation; it should be refactored into a common
+ * component that could be used by both (Shell and UiAutomation).
+ */
+final class Screenshooter {
+
+    private static final String TAG = "Screenshooter";
+
+    /** Rotation constant: Freeze rotation to 0 degrees (natural orientation) */
+    public static final int ROTATION_FREEZE_0 = Surface.ROTATION_0;
+
+    /** Rotation constant: Freeze rotation to 90 degrees . */
+    public static final int ROTATION_FREEZE_90 = Surface.ROTATION_90;
+
+    /** Rotation constant: Freeze rotation to 180 degrees . */
+    public static final int ROTATION_FREEZE_180 = Surface.ROTATION_180;
+
+    /** Rotation constant: Freeze rotation to 270 degrees . */
+    public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
+
+    /**
+     * Takes a screenshot.
+     *
+     * @return The screenshot bitmap on success, null otherwise.
+     */
+    static Bitmap takeScreenshot() {
+        Display display = DisplayManagerGlobal.getInstance()
+                .getRealDisplay(Display.DEFAULT_DISPLAY);
+        Point displaySize = new Point();
+        display.getRealSize(displaySize);
+        final int displayWidth = displaySize.x;
+        final int displayHeight = displaySize.y;
+
+        final float screenshotWidth;
+        final float screenshotHeight;
+
+        final int rotation = display.getRotation();
+        switch (rotation) {
+            case ROTATION_FREEZE_0: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_90: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            case ROTATION_FREEZE_180: {
+                screenshotWidth = displayWidth;
+                screenshotHeight = displayHeight;
+            } break;
+            case ROTATION_FREEZE_270: {
+                screenshotWidth = displayHeight;
+                screenshotHeight = displayWidth;
+            } break;
+            default: {
+                throw new IllegalArgumentException("Invalid rotation: "
+                        + rotation);
+            }
+        }
+
+        Log.d(TAG, "Taking screenshot of dimensions " + displayWidth + " x " + displayHeight);
+        // Take the screenshot
+        Bitmap screenShot =
+                SurfaceControl.screenshot((int) screenshotWidth, (int) screenshotHeight);
+        if (screenShot == null) {
+            Log.e(TAG, "Failed to take screenshot of dimensions " + screenshotWidth + " x "
+                    + screenshotHeight);
+            return null;
+        }
+
+        // Rotate the screenshot to the current orientation
+        if (rotation != ROTATION_FREEZE_0) {
+            Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
+                    Bitmap.Config.ARGB_8888);
+            Canvas canvas = new Canvas(unrotatedScreenShot);
+            canvas.translate(unrotatedScreenShot.getWidth() / 2,
+                    unrotatedScreenShot.getHeight() / 2);
+            canvas.rotate(getDegreesForRotation(rotation));
+            canvas.translate(- screenshotWidth / 2, - screenshotHeight / 2);
+            canvas.drawBitmap(screenShot, 0, 0, null);
+            canvas.setBitmap(null);
+            screenShot.recycle();
+            screenShot = unrotatedScreenShot;
+        }
+
+        // Optimization
+        screenShot.setHasAlpha(false);
+
+        return screenShot;
+    }
+
+    private static float getDegreesForRotation(int value) {
+        switch (value) {
+            case Surface.ROTATION_90: {
+                return 360f - 90f;
+            }
+            case Surface.ROTATION_180: {
+                return 360f - 180f;
+            }
+            case Surface.ROTATION_270: {
+                return 360f - 270f;
+            } default: {
+                return 0;
+            }
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 9eb768c..7c8d0f6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -57,8 +57,9 @@
     private static SummaryStats sEmergencyCallStats;
     private static SummaryStats[][] sProxStats; // [reason][near/far]
 
-    public static void tracePickupPulse(boolean withinVibrationThreshold) {
+    public static void tracePickupPulse(Context context, boolean withinVibrationThreshold) {
         if (!ENABLED) return;
+        init(context);
         log("pickupPulse withinVibrationThreshold=" + withinVibrationThreshold);
         (withinVibrationThreshold ? sPickupPulseNearVibrationStats
                 : sPickupPulseNotNearVibrationStats).append();
@@ -76,8 +77,9 @@
         log("pulseFinish");
     }
 
-    public static void traceNotificationPulse(long instance) {
+    public static void traceNotificationPulse(Context context, long instance) {
         if (!ENABLED) return;
+        init(context);
         log("notificationPulse instance=" + instance);
         sNotificationPulseStats.append();
     }
@@ -153,9 +155,9 @@
     public static void traceProximityResult(Context context, boolean near, long millis,
             int pulseReason) {
         if (!ENABLED) return;
+        init(context);
         log("proximityResult reason=" + pulseReasonToString(pulseReason) + " near=" + near
                 + " millis=" + millis);
-        init(context);
         sProxStats[pulseReason][near ? 0 : 1].append();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 661b347..fc0d8bb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -373,7 +373,7 @@
         if (DEBUG) Log.d(mTag, "mScheduleResetsRemaining = " + mScheduleResetsRemaining);
         mNotificationPulseTime = notificationTimeMs;
         if (pulseImmediately) {
-            DozeLog.traceNotificationPulse(0);
+            DozeLog.traceNotificationPulse(mContext, 0);
             requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
         }
         // schedule the rest of the pulses
@@ -442,7 +442,7 @@
             if (NOTIFICATION_PULSE_ACTION.equals(intent.getAction())) {
                 final long instance = intent.getLongExtra(EXTRA_INSTANCE, -1);
                 if (DEBUG) Log.d(mTag, "Received notification pulse intent instance=" + instance);
-                DozeLog.traceNotificationPulse(instance);
+                DozeLog.traceNotificationPulse(mContext, instance);
                 requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
                 rescheduleNotificationPulse(mNotificationLightOn);
             }
@@ -576,7 +576,7 @@
                     resetNotificationResets();
                 }
                 if (mSensor.getType() == Sensor.TYPE_PICK_UP_GESTURE) {
-                    DozeLog.tracePickupPulse(withinVibrationThreshold);
+                    DozeLog.tracePickupPulse(mContext, withinVibrationThreshold);
                 }
             } finally {
                 mWakeLock.release();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 998f50f..cb77d7b 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -31,6 +31,7 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Message;
 import android.util.AttributeSet;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -106,6 +107,11 @@
     private static final Interpolator IME_ADJUST_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
+    private static final long ONE_MS_IN_NS = 1000000;
+    private static final long ONE_S_IN_NS = ONE_MS_IN_NS * 1000;
+
+    private static final int MSG_RESIZE_STACK = 0;
+
     private DividerHandleView mHandle;
     private View mBackground;
     private MinimizedDockShadow mMinimizedShadow;
@@ -150,7 +156,25 @@
     private boolean mDockedStackMinimized;
     private boolean mAdjustedForIme;
     private DividerState mState;
-    private final Handler mHandler = new Handler();
+
+    /**
+     * The offset between vsync-app and vsync-surfaceflinger. See
+     * {@link #calculateAppSurfaceFlingerVsyncOffsetMs} why this is necessary.
+     */
+    private long mSurfaceFlingerOffsetMs;
+
+    private final Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_RESIZE_STACK:
+                    resizeStack(msg.arg1, msg.arg2, (SnapTarget) msg.obj);
+                    break;
+                default:
+                    super.handleMessage(msg);
+            }
+        }
+    };
 
     private final AccessibilityDelegate mHandleDelegate = new AccessibilityDelegate() {
         @Override
@@ -290,6 +314,7 @@
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
         EventBus.getDefault().register(this);
+        mSurfaceFlingerOffsetMs = calculateAppSurfaceFlingerVsyncOffsetMs();
     }
 
     @Override
@@ -298,6 +323,25 @@
         EventBus.getDefault().unregister(this);
     }
 
+    /**
+     * This method calculates the offset between vsync-surfaceflinger and vsync-app. If vsync-app
+     * is a couple of milliseconds before vsync-sf, a touch or animation event that causes the
+     * stacks to be resized are sometimes processed before the vsync-sf tick, and sometimes after,
+     * which leads to jank. Figure out this difference here and then post all the touch/animation
+     * events to start being processed at vsync-sf.
+     *
+     * @return The offset between vsync-app and vsync-sf, or 0 if vsync app happens after vsync-sf.
+     */
+    private long calculateAppSurfaceFlingerVsyncOffsetMs() {
+        Display display = getDisplay();
+
+        // Calculate vsync offset from SurfaceFlinger.
+        // See frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:getDisplayConfigs
+        long vsyncPeriod = (long) (ONE_S_IN_NS / display.getRefreshRate());
+        long sfVsyncOffset = vsyncPeriod - (display.getPresentationDeadlineNanos() - ONE_MS_IN_NS);
+        return Math.max(0, (sfVsyncOffset - display.getAppVsyncOffsetNanos()) / ONE_MS_IN_NS);
+    }
+
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
         if (mStableInsets.left != insets.getStableInsetLeft()
@@ -453,7 +497,7 @@
                 if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
                     SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(
                             mStartPosition, 0 /* velocity */, false /* hardDismiss */);
-                    resizeStack(calculatePosition(x, y), mStartPosition, snapTarget);
+                    resizeStackDelayed(calculatePosition(x, y), mStartPosition, snapTarget);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -532,10 +576,11 @@
             final long endDelay) {
         final boolean taskPositionSameAtEnd = snapTarget.flag == SnapTarget.FLAG_NONE;
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
-        anim.addUpdateListener(animation -> resizeStack((Integer) animation.getAnimatedValue(),
+        anim.addUpdateListener(animation -> resizeStackDelayed((int) animation.getAnimatedValue(),
                 taskPositionSameAtEnd && animation.getAnimatedFraction() == 1f
                         ? TASK_POSITION_SAME
-                        : snapTarget.taskPosition, snapTarget));
+                        : snapTarget.taskPosition,
+                snapTarget));
         Runnable endAction = () -> {
             commitSnapFlags(snapTarget);
             mWindowManagerProxy.setResizing(false);
@@ -551,15 +596,24 @@
 
             @Override
             public void onAnimationCancel(Animator animation) {
+                mHandler.removeMessages(MSG_RESIZE_STACK);
                 mCancelled = true;
             }
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                if (endDelay == 0 || mCancelled) {
+                long delay = 0;
+                if (endDelay != 0) {
+                    delay = endDelay;
+                } else if (mCancelled) {
+                    delay = 0;
+                } else if (mSurfaceFlingerOffsetMs != 0) {
+                    delay = mSurfaceFlingerOffsetMs;
+                }
+                if (delay == 0) {
                     endAction.run();
                 } else {
-                    mHandler.postDelayed(endAction, endDelay);
+                    mHandler.postDelayed(endAction, delay);
                 }
             }
         });
@@ -793,6 +847,17 @@
                 mDisplayHeight, mDividerSize);
     }
 
+    public void resizeStackDelayed(int position, int taskPosition, SnapTarget taskSnapTarget) {
+        if (mSurfaceFlingerOffsetMs != 0) {
+            Message message = mHandler.obtainMessage(MSG_RESIZE_STACK, position, taskPosition,
+                    taskSnapTarget);
+            message.setAsynchronous(true);
+            mHandler.sendMessageDelayed(message, mSurfaceFlingerOffsetMs);
+        } else {
+            resizeStack(position, taskPosition, taskSnapTarget);
+        }
+    }
+
     public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
         calculateBoundsForPosition(position, mDockSide, mDockedRect);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 628cfd5..c575417 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -961,7 +961,6 @@
                 mNotificationGutsExposed = entry.row.getGuts();
                 bindGuts(entry.row);
             }
-            entry.cacheContentViews(mContext, null /* updatedNotification */);
             inflateViews(entry, mStackScroller);
         }
     }
@@ -1585,7 +1584,12 @@
                 entry.notification.getUser().getIdentifier());
 
         final StatusBarNotification sbn = entry.notification;
-        entry.cacheContentViews(mContext, null);
+        try {
+            entry.cacheContentViews(mContext, null);
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Unable to get notification remote views", e);
+            return false;
+        }
 
         final RemoteViews contentView = entry.cachedContentView;
         final RemoteViews bigContentView = entry.cachedBigContentView;
@@ -2354,7 +2358,13 @@
         Notification n = notification.getNotification();
         mNotificationData.updateRanking(ranking);
 
-        boolean applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
+        boolean applyInPlace;
+        try {
+            applyInPlace = entry.cacheContentViews(mContext, notification.getNotification());
+        } catch (RuntimeException e) {
+            Log.e(TAG, "Unable to get notification remote views", e);
+            applyInPlace = false;
+        }
         boolean shouldPeek = shouldPeek(entry, notification);
         boolean alertAgain = alertAgain(entry, n);
         if (DEBUG) {
@@ -2406,7 +2416,10 @@
                     StatusBarIconView.contentDescForNotification(mContext, n));
             entry.icon.setNotification(n);
             entry.icon.set(ic);
-            inflateViews(entry, mStackScroller);
+            if (!inflateViews(entry, mStackScroller)) {
+                handleNotificationError(notification, "Couldn't update remote views for: "
+                        + notification);
+            }
         }
         updateHeadsUp(key, entry, shouldPeek, alertAgain);
         updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 64f205d2..768e5f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -81,8 +81,8 @@
 
     private static final float LOCK_ICON_ACTIVE_SCALE = 1.2f;
 
-    private static final String COUNTER_PANEL_OPEN = "panel_open";
-    private static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
+    static final String COUNTER_PANEL_OPEN = "panel_open";
+    static final String COUNTER_PANEL_OPEN_QS = "panel_open_qs";
     private static final String COUNTER_PANEL_OPEN_PEEK = "panel_open_peek";
 
     private static final Rect mDummyDirtyRect = new Rect(0, 0, 1, 1);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index b623f19..c703128 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2628,12 +2628,16 @@
         if (!mUserSetup) return;
 
         if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key) {
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
             mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */);
         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key) {
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
             if (mNotificationPanel.isFullyCollapsed()) {
                 mNotificationPanel.expand(true /* animate */);
+                MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN, 1);
             } else if (!mNotificationPanel.isInSettings() && !mNotificationPanel.isExpanding()){
                 mNotificationPanel.flingSettings(0 /* velocity */, true /* expand */);
+                MetricsLogger.count(mContext, NotificationPanelView.COUNTER_PANEL_OPEN_QS, 1);
             }
         }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0106f7f0..d9f2bac 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2197,6 +2197,12 @@
     // Night Light on
     SETTINGS_CONDITION_NIGHT_DISPLAY = 492;
 
+    // System navigation key up.
+    ACTION_SYSTEM_NAVIGATION_KEY_UP = 493;
+
+    // System navigation key down.
+    ACTION_SYSTEM_NAVIGATION_KEY_DOWN = 494;
+
     // ---- End N-MR1 Constants, all N-MR1 constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index c9283b2..4bc148b 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -279,6 +279,7 @@
      */
     private void finishUserUnlocking(final UserState uss) {
         final int userId = uss.mHandle.getIdentifier();
+        boolean proceedWithUnlock = false;
         synchronized (mService) {
             // Bail if we ended up with a stale user
             if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
@@ -288,20 +289,24 @@
 
             if (uss.setState(STATE_RUNNING_LOCKED, STATE_RUNNING_UNLOCKING)) {
                 getUserManagerInternal().setUserState(userId, uss.state);
-                uss.mUnlockProgress.start();
-
-                // Prepare app storage before we go any further
-                uss.mUnlockProgress.setProgress(5,
-                        mService.mContext.getString(R.string.android_start_title));
-                mUserManager.onBeforeUnlockUser(userId);
-                uss.mUnlockProgress.setProgress(20);
-
-                // Dispatch unlocked to system services; when fully dispatched,
-                // that calls through to the next "unlocked" phase
-                mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
-                        .sendToTarget();
+                proceedWithUnlock = true;
             }
         }
+
+        if (proceedWithUnlock) {
+            uss.mUnlockProgress.start();
+
+            // Prepare app storage before we go any further
+            uss.mUnlockProgress.setProgress(5,
+                    mService.mContext.getString(R.string.android_start_title));
+            mUserManager.onBeforeUnlockUser(userId);
+            uss.mUnlockProgress.setProgress(20);
+
+            // Dispatch unlocked to system services; when fully dispatched,
+            // that calls through to the next "unlocked" phase
+            mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0, uss)
+                    .sendToTarget();
+        }
     }
 
     /**
@@ -962,6 +967,7 @@
 
     boolean unlockUserCleared(final int userId, byte[] token, byte[] secret,
             IProgressListener listener) {
+        UserState uss;
         synchronized (mService) {
             // TODO Move this block outside of synchronized if it causes lock contention
             if (!StorageManager.isUserKeyUnlocked(userId)) {
@@ -976,7 +982,7 @@
             }
             // Bail if user isn't actually running, otherwise register the given
             // listener to watch for unlock progress
-            final UserState uss = mStartedUsers.get(userId);
+            uss = mStartedUsers.get(userId);
             if (uss == null) {
                 notifyFinished(userId, listener);
                 return false;
@@ -984,8 +990,12 @@
                 uss.mUnlockProgress.addListener(listener);
                 uss.tokenProvided = (token != null);
             }
+        }
 
-            finishUserUnlocking(uss);
+        finishUserUnlocking(uss);
+
+        final ArraySet<Integer> childProfilesToUnlock = new ArraySet<>();
+        synchronized (mService) {
 
             // We just unlocked a user, so let's now attempt to unlock any
             // managed profiles under that user.
@@ -995,11 +1005,16 @@
                 if (parent != null && parent.id == userId && testUserId != userId) {
                     Slog.d(TAG, "User " + testUserId + " (parent " + parent.id
                             + "): attempting unlock because parent was just unlocked");
-                    maybeUnlockUser(testUserId);
+                    childProfilesToUnlock.add(testUserId);
                 }
             }
         }
 
+        final int size = childProfilesToUnlock.size();
+        for (int i = 0; i < size; i++) {
+            maybeUnlockUser(childProfilesToUnlock.valueAt(i));
+        }
+
         return true;
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b22a084..8f9cc47 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2818,7 +2818,6 @@
             for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
                 int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
                 int uid = UserHandle.getUid(user.id, appId);
-                updateRulesForRestrictPowerUL();
                 // Update external firewall rules.
                 updateRuleForAppIdleUL(uid);
                 updateRuleForDeviceIdleUL(uid);
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 21e4165..ce3ed9c 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -57,7 +57,9 @@
 
     private static final String ATTR_VALUE = "value";
     private static final String ATTR_KNOWN_LOCALES = "locales";
-    private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time";
+
+    // Suffix "2" was added to force rescan all packages after the next OTA.
+    private static final String ATTR_LAST_APP_SCAN_TIME = "last-app-scan-time2";
     private static final String KEY_USER_ID = "userId";
     private static final String KEY_LAUNCHERS = "launchers";
     private static final String KEY_PACKAGES = "packages";